2008-11-09 108 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); 
}