从C#中的多个内存文件创建Zip归档文件

当文件当前在内存中时,有没有办法创建包含多个文件的Zip存档? 我想保存的文件实际上只是文本,并存储在我的应用程序的字符串类中。 但我想将多个文件保存在一个独立的存档中。 它们都可以在归档的根目录中。

能够使用SharpZipLib做到这一点会很高兴。

PutNextEntry()使用ZipEntryPutNextEntry() 。 下面显示了如何为文件执行此操作,但对于内存中对象,只需使用MemoryStream

 FileStream fZip = File.Create(compressedOutputFile); ZipOutputStream zipOStream = new ZipOutputStream(fZip); foreach (FileInfo fi in allfiles) { ZipEntry entry = new ZipEntry((fi.Name)); zipOStream.PutNextEntry(entry); FileStream fs = File.OpenRead(fi.FullName); try { byte[] transferBuffer[1024]; do { bytesRead = fs.Read(transferBuffer, 0, transferBuffer.Length); zipOStream.Write(transferBuffer, 0, bytesRead); } while (bytesRead > 0); } finally { fs.Close(); } } zipOStream.Finish(); zipOStream.Close(); 

使用SharpZipLib看起来非常复杂。 这在DotNetZip中要容易得多 。 在v1.9中,代码如下所示:

 using (ZipFile zip = new ZipFile()) { zip.AddEntry("Readme.txt", stringContent1); zip.AddEntry("readings/Data.csv", stringContent2); zip.AddEntry("readings/Index.xml", stringContent3); zip.Save("Archive1.zip"); } 

上面的代码假定stringContent {1,2,3}包含要存储在zip存档中的文件(或条目)中的数据。 第一个条目是“Readme.txt”,它存储在zip存档中的顶级“目录”中。 接下来的两个条目存储在zip存档的“读取”目录中。

字符串以默认编码进行编码。 AddEntry()的重载(此处未显示)允许您显式指定要使用的编码。

如果您在流或字节数组中有内容,而不是字符串,则AddEntry()的重载会接受这些类型。 还有一些重载接受一个Write委托,一个被调用来将数据写入zip的方法。 例如,这可以轻松地将DataSet保存到zip文件中。

DotNetZip是免费的开源软件。

是的,您可以使用SharpZipLib执行此操作 – 当您需要提供要写入的流时,请使用MemoryStream

我遇到了这个问题,使用我创建此类的MSDN示例:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO.Packaging; using System.IO; public class ZipSticle { Package package; public ZipSticle(Stream s) { package = ZipPackage.Open(s, FileMode.Create); } public void Add(Stream stream, string Name) { Uri partUriDocument = PackUriHelper.CreatePartUri(new Uri(Name, UriKind.Relative)); PackagePart packagePartDocument = package.CreatePart(partUriDocument, ""); CopyStream(stream, packagePartDocument.GetStream()); stream.Close(); } private static void CopyStream(Stream source, Stream target) { const int bufSize = 0x1000; byte[] buf = new byte[bufSize]; int bytesRead = 0; while ((bytesRead = source.Read(buf, 0, bufSize)) > 0) target.Write(buf, 0, bytesRead); } public void Close() { package.Close(); } } 

然后你可以像这样使用它:

 FileStream str = File.Open("MyAwesomeZip.zip", FileMode.Create); ZipSticle zip = new ZipSticle(str); zip.Add(File.OpenRead("C:/Users/C0BRA/SimpleFile.txt"), "Some directory/SimpleFile.txt"); zip.Add(File.OpenRead("C:/Users/C0BRA/Hurp.derp"), "hurp.Derp"); zip.Close(); str.Close(); 

您可以将MemoryStream (或任何Stream )传递给ZipSticle.Add例如:

 FileStream str = File.Open("MyAwesomeZip.zip", FileMode.Create); ZipSticle zip = new ZipSticle(str); byte[] fileinmem = new byte[1000]; // Do stuff to FileInMemory MemoryStream memstr = new MemoryStream(fileinmem); zip.Add(memstr, "Some directory/SimpleFile.txt"); memstr.Close(); zip.Close(); str.Close(); 

注意这个答案已经过时了; 从.Net 4.5开始, ZipArchive类允许在内存中压缩文件。 请参阅下面的约翰尼5的答案 ,了解如何使用它。


您也可以使用Serializable对象存储所有字符串

 [Serializable] public class MyStrings { public string Foo { get; set; } public string Bar { get; set; } } 

然后,您可以将其序列化为流以保存它。
为节省空间,您可以使用GZipStream(来自System.IO.Compression)来压缩它。 (注意:GZip是流压缩,不是多个文件的存档)。

也就是说,当然,如果您需要的是实际保存数据,而不是以特定格式为其他软件压缩一些文件。 此外,这将允许您保存除字符串以外的更多类型的数据。

这个函数应该从数据流创建一个字节数组:为了简单起见,我创建了一个简单的界面来处理文件

 public interface IHasDocumentProperties { byte[] Content { get; set; } string Name { get; set; } } public void CreateZipFileContent(string filePath, IEnumerable fileInfos) { using (var memoryStream = new MemoryStream()) using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) { foreach(var fileInfo in fileInfos) { var entry = zipArchive.CreateEntry(fileInfo.Name); using (var entryStream = entry.Open()) { entryStream.Write(fileInfo.Content, 0, fileInfo.Content.Length); } } } using (var fileStream = new FileStream(filePath, FileMode.OpenOrCreate, System.IO.FileAccess.Write)) { memoryStream.CopyTo(fileStream); } } 

我通过添加MemoryStream作为不同Excel文件的来源来利用Cheeso的答案 。 当我下载zip时,文件中没有任何内容。 这可能是我们试图通过AJAX创建和下载文件的方式。

要获取要包含在Zip中的不同Excel文件的内容,我必须将每个文件添加为byte[]

 using (var memoryStream = new MemoryStream()) using (var zip = new ZipFile()) { zip.AddEntry("Excel File 1.xlsx", excelFileStream1.ToArray()); zip.AddEntry("Excel File 2.xlsx", excelFileStream2.ToArray()); // Keep the file off of disk, and in memory. zip.Save(memoryStream); } 

使用StringReader从字符串对象中读取并将它们作为Stream公开。

这应该可以很容易地将它们提供给您的邮政编码代码。