在ZipArchive C#.Net 4.5中创建目录

ZipArchive是ZipArchiveEntries的集合,添加/删除“条目”非常有效。 但似乎没有目录/嵌套“档案”的概念。 理论上,该类与文件系统分离,因为您可以在内存流中完全创建存档。 但是,如果要在归档中添加目录结构,则必须在条目名称前添加路径前缀。

问题:如何扩展ZipArchive以创建更好的界面来创建和管理目录?

例如,将文件添加到目录的当前方法是使用目录路径创建条目:

var entry = _archive.CreateEntry("directory/entryname"); 

而这些方面的东西对我来说似乎更好:

 var directory = _archive.CreateDirectoryEntry("directory"); var entry = _directory.CreateEntry("entryname"); 

您可以使用以下内容,换句话说,手动创建目录结构:

 using (var fs = new FileStream("1.zip", FileMode.Create)) using (var zip = new ZipArchive(fs, ZipArchiveMode.Create)) { zip.CreateEntry("12/3/"); // just end with "/" } 

如果您正在使用可以使用完整.NET的项目,则可以尝试使用ZipFile.CreateFromDirectory方法,如下所述 :

 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); } } } 

当然,只有在基于给定目录创建新的Zips时,这才有效。

根据评论,以前的解决方案不保留目录结构。 如果需要,那么以下代码可能会解决这个问题:

  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); } } 

这是一个可能的解决方案:

 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); } } 

和使用:

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

但我可以预见到嵌套问题。

我知道我迟到了(7.25.2018),

但即使使用递归目录,这对我来说也是完美无缺的。

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) { var fileName = Path.GetFileName(file); archive.CreateEntryFromAny(file, entryName); } } } 

然后你可以打包任何东西,无论是文件还是目录:

 using (var memoryStream = new MemoryStream()) { using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) { archive.CreateEntryFromAny(sourcePath); } } 

使用子文件夹Zip文件夹的递归方法。

 using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; public static async Task 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 + "/"); } }