2008-11-09 42 views
25

Có cách nào để tạo lưu trữ Zip có chứa nhiều tệp, khi các tệp hiện có trong bộ nhớ không? Các tệp tôi muốn lưu thực sự chỉ là văn bản và được lưu trữ trong một lớp chuỗi trong ứng dụng của tôi. Nhưng tôi muốn lưu nhiều tệp trong một kho lưu trữ độc lập. Tất cả chúng đều có thể nằm trong thư mục gốc của kho lưu trữ.Tạo lưu trữ Zip từ nhiều tệp trong bộ nhớ trong C#

Thật tuyệt khi có thể thực hiện việc này bằng SharpZipLib.

Trả lời

25

Sử dụng ZipEntryPutNextEntry() cho việc này. Các chương trình sau làm thế nào để làm điều đó cho một tập tin, nhưng đối với một đối tượng trong bộ nhớ chỉ cần sử dụng một 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

Bạn có thể sử dụng 'using()' trên 'zipOStream' thay vì' Close() 'không? –

+0

Có, ZipOutputStream là dùng một lần – Mike

+2

Nếu bạn đang sử dụng .NET 4.5 có một lớp Zip được xây dựng trong đó dễ dàng hơn nhiều để sử dụng hơn abomination này (SharpZipLib). –

5

Có, bạn có thể sử dụng SharpZipLib để thực hiện việc này - khi bạn cần cung cấp luồng để ghi, sử dụng MemoryStream.

-1

Sử dụng StringReader để đọc từ các đối tượng chuỗi của bạn và hiển thị chúng dưới dạng Dòng s.

Điều đó sẽ giúp bạn dễ dàng cấp chúng cho mã xây dựng zip của mình.

2

Lưu ý câu trả lời này là lỗi thời; kể từ .Net 4.5, lớp ZipArchive cho phép nén tệp trong bộ nhớ. Xem johnny 5's answer below để biết cách sử dụng.


Bạn cũng có thể làm điều đó một chút khác nhau, sử dụng một đối tượng Serializable để lưu trữ tất cả các chuỗi

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

Sau đó, bạn có thể serialize nó thành một dòng suối để lưu nó.
Để tiết kiệm dung lượng, bạn có thể sử dụng GZipStream (Từ System.IO.Compression) để nén. (lưu ý: GZip là nén luồng, không phải là tệp lưu trữ nhiều tệp).

Tức là, tất nhiên nếu những gì bạn cần thực sự là lưu dữ liệu và không nén một vài tệp ở định dạng cụ thể cho phần mềm khác. Ngoài ra, điều này sẽ cho phép bạn lưu nhiều loại dữ liệu hơn trừ chuỗi.

+0

Tôi muốn loại tệp lưu thành định dạng cho phép người dùng mở tệp và kéo ra các phần cụ thể, nhưng đó có thể là điều tốt nhất/dễ nhất để làm ... –

+0

@Configurator Fancy nhìn thấy bạn ở đây –

19

Sử dụng SharpZipLib cho điều này có vẻ khá phức tạp. Điều này dễ dàng hơn rất nhiều trong DotNetZip. Trong v1.9, mã trông giống như sau:

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

Mã trên giả định stringContent {1,2,3} chứa dữ liệu được lưu trữ trong tệp (hoặc mục) trong lưu trữ zip. Mục nhập đầu tiên là "Readme.txt" và nó được lưu trữ ở cấp cao nhất "Thư mục" trong kho lưu trữ zip. Hai mục tiếp theo được lưu trữ trong thư mục "readings" trong kho lưu trữ zip.

Các chuỗi được mã hóa bằng mã hóa mặc định. Có quá tải AddEntry(), không được hiển thị ở đây, cho phép bạn chỉ định rõ ràng mã hóa để sử dụng.

Nếu bạn có nội dung trong luồng hoặc mảng byte, không phải chuỗi, có quá tải cho AddEntry() chấp nhận các loại đó. Ngoài ra còn có quá tải chấp nhận một đại biểu viết, một phương pháp của bạn được gọi để ghi dữ liệu vào zip. Điều này làm việc để dễ dàng lưu một số liệu vào một tập tin zip, ví dụ.

DotNetZip là nguồn mở và miễn phí.

4

tôi đi qua vấn đề này, bằng cách sử dụng ví dụ MSDN Tôi tạo ra lớp này:

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

Sau đó bạn có thể sử dụng nó như thế này:

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

Bạn có thể vượt qua một MemoryStream (hoặc bất kỳ Stream) đến ZipSticle.Add chẳng hạn như:

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

Chức năng này nên tạo một mảng byte từ một dòng dữ liệu: tôi đã tạo ra một giao diện đơn giản để xử lý các file vì đơn giản

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

Tôi đã sử dụng Cheeso's answer bằng cách thêm MemoryStream s như là nguồn gốc của các file Excel khác nhau. Khi tôi tải xuống tệp nén, các tệp không có gì trong chúng. Đây có thể là cách chúng tôi đang cố gắng tạo và tải xuống một tệp trên AJAX.

Để lấy nội dung của các tệp Excel khác nhau được bao gồm trong Zip, tôi phải thêm từng tệp dưới dạng 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); 
} 
Các vấn đề liên quan