Creating Directories in a ZipArchive C# .Net 4.5

后端 未结 8 1876
星月不相逢
星月不相逢 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:08

    If you are working on a project that can use full .NET you may try to use the ZipFile.CreateFromDirectory method, as explained here:

    using System;
    using System.IO;
    using System.IO.Compression;
    
    namespace ConsoleApplication
    {
        class Program
        {
            static void Main(string[] args)
            {
                string startPath = @"c:\example\start";
                string zipPath = @"c:\example\result.zip";
                string extractPath = @"c:\example\extract";
    
                ZipFile.CreateFromDirectory(startPath, zipPath, CompressionLevel.Fastest, true);
    
                ZipFile.ExtractToDirectory(zipPath, extractPath);
            }
        }
    }
    

    Of course this will only work if you are creating new Zips based on a given directory.

    As per the comment, the previous solution does not preserve the directory structure. If that is needed, then the following code might address that:

        var InputDirectory = @"c:\example\start";
        var OutputFilename = @"c:\example\result.zip";
        using (Stream zipStream = new FileStream(Path.GetFullPath(OutputFilename), FileMode.Create, FileAccess.Write))
        using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create))
        {
            foreach(var filePath in System.IO.Directory.GetFiles(InputDirectory,"*.*",System.IO.SearchOption.AllDirectories))
            {
                var relativePath = filePath.Replace(InputDirectory,string.Empty);
                using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                using (Stream fileStreamInZip = archive.CreateEntry(relativePath).Open())
                    fileStream.CopyTo(fileStreamInZip);
            }
        }
    
    0 讨论(0)
  • 2020-12-03 10:16

    You can use something like the following, in other words, create the directory structure by hand:

    using (var fs = new FileStream("1.zip", FileMode.Create))
    using (var zip = new ZipArchive(fs, ZipArchiveMode.Create))
    {
        zip.CreateEntry("12/3/"); // just end with "/"
    }
    
    0 讨论(0)
  • 2020-12-03 10:19

    I know I'm late to the party (7.25.2018),

    this works flawlessly to me, even with recursive directories.

    Firstly, remember to install the NuGet package:

    Install-Package System.IO.Compression

    And then, Extension file for ZipArchive:

     public static class ZipArchiveExtension {
    
         public static void CreateEntryFromAny(this ZipArchive archive, string sourceName, string entryName = "") {
             var fileName = Path.GetFileName(sourceName);
             if (File.GetAttributes(sourceName).HasFlag(FileAttributes.Directory)) {
                 archive.CreateEntryFromDirectory(sourceName, Path.Combine(entryName, fileName));
             } else {
                 archive.CreateEntryFromFile(sourceName, Path.Combine(entryName, fileName), CompressionLevel.Fastest);
             }
         }
    
         public static void CreateEntryFromDirectory(this ZipArchive archive, string sourceDirName, string entryName = "") {
             string[] files = Directory.GetFiles(sourceDirName).Concat(Directory.GetDirectories(sourceDirName)).ToArray();
             archive.CreateEntry(Path.Combine(entryName, Path.GetFileName(sourceDirName)));
             foreach (var file in files) {
                 archive.CreateEntryFromAny(file, entryName);
             }
         }
     }
    

    And then you can pack anything, whether it is file or directory:

    using (var memoryStream = new MemoryStream()) {
        using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) {
            archive.CreateEntryFromAny(sourcePath);
        }
    }
    
    0 讨论(0)
  • 2020-12-03 10:20

    My answer is based on the Val's answer, but a little improved for performance and without producing empty files in ZIP.

    public static class ZipArchiveExtensions
    {
        public static void CreateEntryFromAny(this ZipArchive archive, string sourceName, string entryName = "")
        {
            var fileName = Path.GetFileName(sourceName);
            if (File.GetAttributes(sourceName).HasFlag(FileAttributes.Directory))
            {
                archive.CreateEntryFromDirectory(sourceName, Path.Combine(entryName, fileName));
            }
            else
            {
                archive.CreateEntryFromFile(sourceName, Path.Combine(entryName, fileName), CompressionLevel.Optimal);
            }
        }
    
        public static void CreateEntryFromDirectory(this ZipArchive archive, string sourceDirName, string entryName = "")
        {
            var files = Directory.EnumerateFileSystemEntries(sourceDirName);
            foreach (var file in files)
            {
                archive.CreateEntryFromAny(file, entryName);
            }
        }
    }
    

    Example of using:

    // Create and open a new ZIP file
                    using (var zip = ZipFile.Open(ZipPath, ZipArchiveMode.Create))
                    {
                        foreach (string file in FILES_LIST)
                        {
                            // Add the entry for each file
                            zip.CreateEntryFromAny(file);
                        }
                    }
    
    0 讨论(0)
  • 2020-12-03 10:23

    Here is one possible solution:

    public static class ZipArchiveExtension
    {
        public static ZipArchiveDirectory CreateDirectory(this ZipArchive @this, string directoryPath)
        {
            return new ZipArchiveDirectory(@this, directoryPath);
        }
    }
    
    public class ZipArchiveDirectory
    {
        private readonly string _directory;
        private ZipArchive _archive;
    
        internal ZipArchiveDirectory(ZipArchive archive, string directory)
        {
            _archive = archive;
            _directory = directory;
        }
    
        public ZipArchive Archive { get{return _archive;}}
    
        public ZipArchiveEntry CreateEntry(string entry)
        {
            return _archive.CreateEntry(_directory + "/" + entry);
        }
    
        public ZipArchiveEntry CreateEntry(string entry, CompressionLevel compressionLevel)
        {
            return _archive.CreateEntry(_directory + "/" + entry, compressionLevel);
        }
    }
    

    and used:

    var directory = _archive.CreateDirectory(context);
    var entry = directory.CreateEntry(context);
    var stream = entry.Open();
    

    but I can foresee problems with nesting, perhaps.

    0 讨论(0)
  • 2020-12-03 10:28

    Use the recursive approach to Zip Folders with Subfolders.

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.IO.Compression;
    
    public static async Task<bool> ZipFileHelper(IFolder folderForZipping, IFolder folderForZipFile, string zipFileName)
    {
        if (folderForZipping == null || folderForZipFile == null
            || string.IsNullOrEmpty(zipFileName))
        {
            throw new ArgumentException("Invalid argument...");
        }
    
        IFile zipFile = await folderForZipFile.CreateFileAsync(zipFileName, CreationCollisionOption.ReplaceExisting);
    
        // Create zip archive to access compressed files in memory stream
        using (MemoryStream zipStream = new MemoryStream())
        {
            using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
            {
                await ZipSubFolders(folderForZipping, zip, "");
            }
    
            zipStream.Position = 0;
            using (Stream s = await zipFile.OpenAsync(FileAccess.ReadAndWrite))
            {
                zipStream.CopyTo(s);
            }
        }
        return true;
    }
    
    //Create zip file entry for folder and subfolders("sub/1.txt")
    private static async Task ZipSubFolders(IFolder folder, ZipArchive zip, string dir)
    {
        if (folder == null || zip == null)
            return;
    
        var files = await folder.GetFilesAsync();
        var en = files.GetEnumerator();
        while (en.MoveNext())
        {
            var file = en.Current;
            var entry = zip.CreateEntryFromFile(file.Path, dir + file.Name);                
        }
    
        var folders = await folder.GetFoldersAsync();
        var fEn = folders.GetEnumerator();
        while (fEn.MoveNext())
        {
            await ZipSubFolders(fEn.Current, zip, dir + fEn.Current.Name + "/");
        }
    }
    
    0 讨论(0)
提交回复
热议问题