2

I'm struggling with creating zip archives and could use some guidance from more experienced coders. I am attempting to create a zip archive of 800 folders and subfolders and about 8,000 files with the following method. This code works in so far that it will create an archive but there is no internal directory structure. All 8,000 files are stored in the zip in a single flat list. Is there a way to do this so that its like a typical zip archive in that the folder structure is also stored in the zip file? I am aware of the ZipFile.CreateFromDirectory() method [which does preserve folder structure] but do not want to use it because it fails in the event that a file is locked. I am also aware that there are other libraries but I'd like to use the C# library if that is possible. Any guidance will be appreciated. Thank you.

    {
        SearchOption searchOption = SearchOption.AllDirectories;

        IEnumerable<string> fileSystem;
        fileSystem = Directory.EnumerateFileSystemEntries(_zipRoot, "*.*", searchOption);
        
        
        using (ZipArchive archive = ZipFile.Open(_zipPath, ZipArchiveMode.Create))
        {
            foreach (var fPath in fileSystem)
            {
                try
                {
                    archive.CreateEntryFromFile(fPath,Path.GetFileName(fPath));
                }
                catch 
                {
                    FailedFiles.Add(fPath);
                    Debug.Log(fPath);
                }
                
            }
        }
        Debug.Log($"{FailedFiles.Count} files failed to archive.");
        
    }```
Dan
  • 59
  • 6
  • 1
    `but do not want to use it because it fails in the event that a file is locked.` Copy the files to a new location. Create the zip from there. – mjwills Jul 19 '21 at 06:25
  • 2
    https://stackoverflow.com/questions/15133626/creating-directories-in-a-ziparchive-c-sharp-net-4-5 may be worth a read. – mjwills Jul 19 '21 at 06:29

1 Answers1

2

After reading the thread posted by @mjwills which discusses several approaches, the following code suggested by @Curti works like a charm.


    public static void StructuredZip(this ZipArchive archive, string sourceDirName, CompressionLevel compressionLevel = CompressionLevel.Fastest)
    {
        int fileCount = 0;
        int folderCount = 0;
        int failedCount = 0;
        var folders = new Stack<string>();

        folders.Push(sourceDirName);

        do
        {
            var currentFolder = folders.Pop();

            folderCount++;
            foreach (var item in Directory.GetFiles(currentFolder))
            {
                try
                {
                    archive.CreateEntryFromFile(item, item.Substring(sourceDirName.Length + 1),
                        compressionLevel);
                    fileCount++;
                }
                catch
                {
                    failedCount++;
                }
            }

            foreach (var item in Directory.GetDirectories(currentFolder))
            {
                folders.Push(item);
            }
        } 
        while (folders.Count > 0);
        
        Debug.Log($"Archived {fileCount} in {folderCount} folders. There were {failedCount} failed files!");
    }
 }


using (var zip = ZipFile.Open(_zipPath, ZipArchiveMode.Create))
        {
            zip.StructuredZip(_zipRoot);
        }
Dan
  • 59
  • 6
  • Worked really well. I added the following in the foreach on the list of directories to make sure empty directories could be preserved: ```var entryName = folder.Substring(sourceDirectory.Length + 1) + Path.DirectorySeparatorChar; zip.CreateEntry(entryName, CompressionLevel.NoCompression);``` – StayOnTarget Sep 30 '22 at 21:31