2008-11-09 106 views
25

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

这将是很好能够使用SharpZipLib做到这一点。

回答

25

为此,使用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(); 
+0

您可以在`zipOStream`上使用'using()'而不是`Close()`吗? – 2008-12-21 03:47:46

+0

是的,ZipOutputStream是一次性的 – Mike 2009-08-10 01:19:32

5

是的,你可以使用SharpZipLib来做到这一点 - 当你需要提供一个流写入,使用MemoryStream

-1

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

这应该很容易将它们提供给您的zip构建代码。

2

注意这个答案已经过时;自.NET 4.5开始,ZipArchive类允许在内存中压缩文件。有关如何使用它,请参阅johnny 5's answer below


你也可以做到这一点有点不同,采用序列化对象来存储所有字符串

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

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

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

19

使用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是免费且开源的。

4

我碰到过这样的问题,使用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(); 
2

此功能应创建从数据流的字节数组:我已经创建了一个简单的接口,用于通过添加MemoryStream S作为不同的Excel文件的源文件处理为简单起见

public interface IHasDocumentProperties 
{ 
    byte[] Content { get; set; } 
    string Name { get; set; } 
} 

public void CreateZipFileContent(string filePath, IEnumerable<IHasDocumentProperties> 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); 
    } 
} 
0
我被利用 Cheeso's answer

。当我下载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); 
}