Creating Directories in a ZipArchive C# .Net 4.5

后端 未结 8 1877
星月不相逢
星月不相逢 2020-12-03 10:06

A ZipArchive is a collection of ZipArchiveEntries, and adding/removing \"Entries\" works nicely. But it appears there is no notion of directories / nested \"Archives\". In t

相关标签:
8条回答
  • 2020-12-03 10:28

    I don't like recursion as it was proposed by @Val, @sDima, @Nitheesh. Potentially it leads to the StackOverflowException because the stack has limited size. So here is my two cents with tree traversal.

    public static class ZipArchiveExtensions
    {
        public static void CreateEntryFromDirectory(this ZipArchive archive, string sourceDirName, CompressionLevel compressionLevel = CompressionLevel.Fastest)
        {
            var folders = new Stack<string>();
            folders.Push(sourceDirName);
            
            do
            {
                var currentFolder = folders.Pop();
                Directory.GetFiles(currentFolder).ForEach(f => archive.CreateEntryFromFile(f, f.Substring(sourceDirName.Length+1), compressionLevel));
                Directory.GetDirectories(currentFolder).ForEach(d => folders.Push(d));
            } while (folders.Count > 0);
        }
    }
    
    0 讨论(0)
  • 2020-12-03 10:30

    I was also looking for a similar solution and found @Val & @sDima's solution more promising to me. But I found some issues with the code and fixed them to use with my code.

    Like @sDima, I also decided to use Extension to add more functionality to ZipArchive.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.IO.Compression;
    using System.IO;
    
    namespace ZipTest
    {
       public static class ZipArchiveExtensions
       {
          public static void CreateEntryFromAny(this ZipArchive archive, string sourceName, string entryName, CompressionLevel compressionLevel = CompressionLevel.Optimal)
        {
            try
            {
                if (File.GetAttributes(sourceName).HasFlag(FileAttributes.Directory))
                {
                    archive.CreateEntryFromDirectory(sourceName, entryName, compressionLevel);
                }
                else
                {
                    archive.CreateEntryFromFile(sourceName, entryName, compressionLevel);
                }
            }
            catch
            {
                throw;
            }
        }
    
        public static void CreateEntryFromDirectory(this ZipArchive archive, string sourceDirName, string entryName, CompressionLevel compressionLevel)
        {
            try
            {
                var files = Directory.EnumerateFileSystemEntries(sourceDirName);
                if (files.Any())
                {
                    foreach (var file in files)
                    {
                        var fileName = Path.GetFileName(file);
                        archive.CreateEntryFromAny(file, Path.Combine(entryName, fileName), compressionLevel);
                    }
                }
                else
                {
                    //Do a folder entry check.
                    if (!string.IsNullOrEmpty(entryName) && entryName[entryName.Length - 1] != '/')
                    {
                        entryName += "/";
                    }
    
                    archive.CreateEntry(entryName, compressionLevel);
                }
            }
            catch
            {
                throw;
            }
          }
        }
      }
    

    You can try the extension using the simple given below,

     class Program
     {
        static void Main(string[] args)
        {
            string filePath = @"C:\Users\WinUser\Downloads\Test.zip";
            string dirName = Path.GetDirectoryName(filePath);
           
            if (File.Exists(filePath))
                File.Delete(filePath);
    
            using (ZipArchive archive = ZipFile.Open(filePath, ZipArchiveMode.Create))
            {
                archive.CreateEntryFromFile( @"C:\Users\WinUser\Downloads\file1.jpg", "SomeFolder/file1.jpg", CompressionLevel.Optimal);
                archive.CreateEntryFromDirectory(@"C:\Users\WinUser\Downloads\MyDocs", "OfficeDocs", CompressionLevel.Optimal);
                archive.CreateEntryFromAny(@"C:\Users\WinUser\Downloads\EmptyFolder", "EmptyFolder", CompressionLevel.Optimal);
            };
    
            using (ZipArchive zip = ZipFile.OpenRead(filePath))
            {
                string dirExtract = @"C:\Users\WinUser\Downloads\Temp";
                if (Directory.Exists(dirExtract))
                {
                    Directory.Delete(dirExtract, true);
                }
    
                zip.ExtractToDirectory(dirExtract);
            }
         }
       }
    

    I tried to keep the exact behavior of standard CreateEntryFromFilefrom the .Net Framework for extension methods.

    To use the sample code given, add a reference to System.IO.Compression.dll and System.IO.Compression.FileSystem.dll.

    Following are the advantages of this extension class

    1. Recursive adding of folder content.
    2. Support for an empty folder.
    0 讨论(0)
提交回复
热议问题