0 votes
ago by (140 points)

From Windows 10 on it is possible to extend the max path length of a file or directory up to 32767 character.

This can be set in the registry described here:
https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry#enable-long-paths-in-windows-10-version-1607-and-later

Can Rebex zip use this or work with this setting?
I need to handle very long file paths as our customers create them pretty often.

Thanks

Applies to: Rebex ZIP

1 Answer

0 votes
ago by (74.5k points)

In general, Rebex ZIP works with path using .NET System.IO API. If the system can handle long paths, then Rebex ZIP will handle it as well.

For example, I have just tested that there is no issue with long paths on .NET 6, .NET 8 and .NET 9, but I got System.IO.DirectoryNotFoundException on .NET 4.8.
In both cases the LongPathsEnabled registry value has no effect on the functionality.

If you target .NET 4.8 (or lower) there is known workaround for long paths. You have to enable support for long path in app.config file like this:

<runtime>
    <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
</runtime>

Then in your code you have to use full UNC paths such as:

string path = @"\\?\c:\my_very_long_path";

Finally, Rebex ZIP can operate on streams, which enables you to delegate work with long paths to a different API. You only need to provide a seekable stream for ZipArchive. For adding or extracting files even non-seekable streams would be enough.

ago by (140 points)
Hi, I´m sorry but I don´t understand what you mean with that I have to use full UNC paths. At what point/definition? For the destination zip file or for the files and folders to be zipped? Or something else?
ago by (74.5k points)
You have to use full UNC paths for all long local disk paths (only on .NET 4.8 or lower).
It means .ZIP file path, path of files to add and path of files to extract.

For example, you can extract all files from ZIP using UNC paths like this:

    string outPath = @"\\?\c:\extracted";
    foreach (var item in zip.GetItems("*", TraversalMode.Recursive, ArchiveItemTypes.Files))
    {
        Console.WriteLine("Extracting file to: {0}", outPath + item.Path);
        zip.ExtractFile(item.Path, outPath + item.Path, ActionOnExistingFiles.OverwriteAll);
    }
ago by (140 points)
Ok, I´ve tried this with this C# (.NetFramework 4.8) sample:

        private string zipFilePath = @"\\?\D:\Data\TrainingFile.zip";

        public TestClass()
        {
            string source = @"\\?\D:\Projects\MyData\*";

            CreateZipFile(zipFilePath, source);
        }

        internal void CreateZipFile(string zipFilePath, string sourceDirectory)
        {
            try
            {
                using (ZipArchive archive = new ZipArchive(zipFilePath))
                {
                    ArchiveOperationResult result = archive.Add(
                        sourceDirectory,
                        "/",
                        TraversalMode.Recursive,
                        TransferMethod.Copy,
                        ActionOnExistingFiles.OverwriteAll
                    );

                    Console.WriteLine(
                        "Added {0} file(s), {1} byte(s) to {2}.",
                        result.FilesAffected,
                        result.FilesUncompressedLength,
                        archive.FilePath
                    );
                }
            }
            catch (Exception ex)
            {
                string exText = ex.Message;
            }
        }

But the "Add" failed with an exception saying:
"Illegal use of wildcards in path.
Parameter name: sourcePathOrMask"

Note: I´m using Rebex zip version 7.0.8720.0
ago by (74.5k points)
This is known limitation, which can be easily worked around using FileSet like this:

    ArchiveOperationResult result = archive.Add(
        new FileSet(sourceDirectory, "*"),
        "/",
        TransferMethod.Copy,
        ActionOnExistingFiles.OverwriteAll);

For source directory use the UNC path without trailing asterisk (*) like this:

    string source = @"\\?\D:\Projects\MyData";
ago by (140 points)
One step further.
I changed this to use the FileSet object. This worked then with data not containing very long file paths.

Then I changed the sourceDirectory to a folder containing a very long file path.
And then it failed agin with the exception text:
Rebex.IO.Compression.ZipException: 'Cannot determine whether a file that was previously found exists ('D:\Labtronic Data\Projects\Proj_BiaxFrameSimRig\WorkSpaces\OrdnerMit20CharsABCD\NochOrdnerMit20Chars\UndNochEinerOrdner20\AuchEin20erOrdnerABC\LangerOrdnerMit20ABC\Ebene6UnterOrdnerABC\Layer820erOrdnerABCD\NeunterLayerOrdnerAB\DriveFileMitExtremLangemDateiNamenZum.dmd').'

System settings:
"LongPathsEnabled" is set to 1 under "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem"

app.config is:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
    </startup>
    <runtime>
        <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
    </runtime>   
</configuration>

app.manifest contains:
 <application xmlns="urn:schemas-microsoft-com:asm.v3">
   <windowsSettings>
     <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
   </windowsSettings>
 </application>
ago by (74.5k points)
It seems that you are still using non-UNC path somewhere, because the path in the exception says 'D:\Labtronic...' instead of '\\?\D:\Labtronic...'
ago by (140 points)
You are right.
The source path was (again) not an UNC path.
Now the compress worked fine.
Thank you.
Tomorrow I´ll test the unpacking.
...