2009-02-03 44 views
46

Tôi có một loạt các tệp ZIP cần tuyệt đối để sắp xếp lại và trích xuất một số phân cấp. Những gì tôi có thể làm, hiện tại, là tạo cấu trúc thư mục và di chuyển các tệp zip đến vị trí thích hợp. Các pho mát thần bí mà tôi đang thiếu là một phần mà trích xuất các tập tin từ kho lưu trữ ZIP.Giải nén tập tin từ kho lưu trữ Zip bằng lập trình bằng C# và System.IO.Packaging

Tôi đã xem các bài viết MSDN trên lớp ZipArchive và hiểu chúng một cách hợp lý. Tôi cũng đã xem số VBScript ways to extract. Đây không phải là một lớp phức tạp nên việc trích xuất nội dung nên khá đơn giản. Trong thực tế, nó hoạt động "chủ yếu". Tôi đã bao gồm mã hiện tại của mình bên dưới để tham khảo.

using (ZipPackage package = (ZipPackage)Package.Open(@"..\..\test.zip", FileMode.Open, FileAccess.Read)) 
{ 
    PackagePartCollection packageParts = package.GetParts(); 
    foreach (PackageRelationship relation in packageParts) 
    { 
     //Do Stuff but never gets here since packageParts is empty. 
    } 
} 

Vấn đề có vẻ là ở đâu đó trong GetParts (hoặc Nhận Bất cứ điều gì cho rằng vấn đề). Dường như gói, trong khi mở, trống. Đào sâu hơn trình gỡ lỗi cho thấy rằng thành viên private _zipArchive cho thấy rằng nó thực sự có các phần. Các bộ phận có tên đúng và mọi thứ. Tại sao chức năng GetParts không truy xuất được? Tôi đã cố gắng đúc mở cho một ZipArchive và điều đó đã không giúp đỡ. Grrr.

+1

FYI, tôi đã đăng một yêu cầu trên MS Connect để thêm hỗ trợ cho kho lưu trữ ZIP chung. Bạn cũng có thể bỏ phiếu tại https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=477393 –

Trả lời

45

Nếu bạn đang thao tác tệp ZIP, bạn có thể muốn xem thư viện bên thứ ba để trợ giúp bạn.

Ví dụ: DotNetZip, đã được cập nhật gần đây. Phiên bản hiện tại là v1.8.Dưới đây là một ví dụ để tạo ra một zip:

using (ZipFile zip = new ZipFile()) 
{ 
    zip.AddFile("c:\\photos\\personal\\7440-N49th.png"); 
    zip.AddFile("c:\\Desktop\\2005_Annual_Report.pdf"); 
    zip.AddFile("ReadMe.txt"); 

    zip.Save("Archive.zip"); 
} 

Dưới đây là một ví dụ để cập nhật một zip hiện có; bạn không cần phải giải nén các tập tin để làm điều đó:

using (ZipFile zip = ZipFile.Read("ExistingArchive.zip")) 
{ 
    // 1. remove an entry, given the name 
    zip.RemoveEntry("README.txt"); 

    // 2. Update an existing entry, with content from the filesystem 
    zip.UpdateItem("Portfolio.doc"); 

    // 3. modify the filename of an existing entry 
    // (rename it and move it to a sub directory) 
    ZipEntry e = zip["Table1.jpg"]; 
    e.FileName = "images/Figure1.jpg"; 

    // 4. insert or modify the comment on the zip archive 
    zip.Comment = "This zip archive was updated " + System.DateTime.ToString("G"); 

    // 5. finally, save the modified archive 
    zip.Save(); 
} 

đây là một ví dụ rằng chiết xuất mục:

using (ZipFile zip = ZipFile.Read("ExistingZipFile.zip")) 
{ 
    foreach (ZipEntry e in zip) 
    { 
    e.Extract(TargetDirectory, true); // true => overwrite existing files 
    } 
} 

DotNetZip hỗ trợ ký tự đa byte trong tên tập tin, mã hóa Zip, mã hóa AES, suối , Unicode, tự giải nén lưu trữ. Ngoài ra, ZIP64, cho độ dài tập tin lớn hơn 0xFFFFFFFF, hoặc cho lưu trữ với hơn 65535 mục.

miễn phí. mã nguồn mở

nhận được nó ở codeplex

+1

cheeso, tôi đồng ý wit bạn ,,, nhưng tôi không thể xây dựng mã mà tôi đã tải về frm codeplex .. xin vui lòng cho biết làm thế nào để xây dựng .. nếu tôi xây dựng giải pháp chính của nó ném rất nhiều hoặc lỗi .. i dont no how to xây dựng – Naruto

+4

tại sao bạn xây dựng nó? Có một nhị phân. Tải xuống tệp DLL. – Cheeso

+1

Tại sao nên sử dụng thư viện của bên thứ 3, không nên có không gian tên 'System.IO.Packaging' đủ? Hoặc là đoạn cuối cùng của bạn chi tiết những gì được xây dựng trong NET framework. Zip chức năng không ** không ** bao gồm? –

44

Từ MSDN,

Trong ví dụ này, lớp gói được sử dụng (như trái ngược với ZipPackage.) Sau khi làm việc với cả hai, tôi đã chỉ nhìn thấy flakiness xảy ra khi có tham nhũng trong file zip. Không nhất thiết phải tham nhũng mà ném Windows extractor hoặc Winzip, nhưng một cái gì đó mà các thành phần bao bì có xử lý sự cố.

Hy vọng điều này sẽ hữu ích, có thể nó có thể cung cấp cho bạn một giải pháp thay thế để gỡ lỗi vấn đề.

using System; 
using System.IO; 
using System.IO.Packaging; 
using System.Text; 

class ExtractPackagedImages 
{ 
    static void Main(string[] paths) 
    { 
     foreach (string path in paths) 
     { 
      using (Package package = Package.Open(
       path, FileMode.Open, FileAccess.Read)) 
      { 
       DirectoryInfo dir = Directory.CreateDirectory(path + " Images"); 
       foreach (PackagePart part in package.GetParts()) 
       { 
        if (part.ContentType.ToLowerInvariant().StartsWith("image/")) 
        { 
         string target = Path.Combine(
          dir.FullName, CreateFilenameFromUri(part.Uri)); 
         using (Stream source = part.GetStream(
          FileMode.Open, FileAccess.Read)) 
         using (Stream destination = File.OpenWrite(target)) 
         { 
          byte[] buffer = new byte[0x1000]; 
          int read; 
          while ((read = source.Read(buffer, 0, buffer.Length)) > 0) 
          { 
           destination.Write(buffer, 0, read); 
          } 
         } 
         Console.WriteLine("Extracted {0}", target); 
        } 
       } 
      } 
     } 
     Console.WriteLine("Done"); 
    } 

    private static string CreateFilenameFromUri(Uri uri) 
    { 
     char [] invalidChars = Path.GetInvalidFileNameChars(); 
     StringBuilder sb = new StringBuilder(uri.OriginalString.Length); 
     foreach (char c in uri.OriginalString) 
     { 
      sb.Append(Array.IndexOf(invalidChars, c) < 0 ? c : '_'); 
     } 
     return sb.ToString(); 
    } 
} 
+24

Nhìn vào mã đó, tôi chỉ giơ giày lên. PackagePartCollection? PartRelationship? PackagePart? Phần URI? ToLowerInvariant? Tất cả những gì tôi muốn là một FILE ZIP ... – Cheeso

+2

Vâng, đó sẽ là một phần các nhà phát triển OpenPackage dường như quên. Làm việc với OpenPackage là nhiều hơn về làm việc với các thành phần ảo, như trái ngược với biểu diễn vật lý. – jro

+15

Đây là câu trả lời duy nhất trả lời câu hỏi thực sự về cách sử dụng X để thực hiện Y, nó có mã và mọi thứ, không đi tiếp tuyến và chỉ cách sử dụng Z để thực hiện Y, và nó có ít nhất phiếu bầu? Hãy đến với mọi người. – a7drew

29

Từ "ZipPackage Class" (MSDN):

Trong khi gói được lưu trữ dưới dạng tệp Zip * thông qua các lớp ZipPackage, tất cả các file Zip không ZipPackages. ZipPackage có các yêu cầu đặc biệt như tên tệp (phần) tuân thủ URI và tệp "[Content_Types] .xml" xác định các loại MIME cho tất cả các tệp có trong Gói. Lớp ZipPackage không thể được sử dụng để mở các tệp Zip đơn phương không tuân theo tiêu chuẩn quy ước mở bao bì.

Để biết thêm chi tiết xem Phần 9.2 "Mapping để ZIP lưu trữ" của tiêu chuẩn ECMA International "Open ước bao bì", http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(DOCX).zip (342Kb) hoặc http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(PDF).zip (1.3MB)

* Bạn chỉ có thể thêm" .zip "để mở rộng bất kỳ tệp dựa trên ZipPackage nào (.docx, .xlsx, .pptx, v.v.) để mở nó trong tiện ích Zip yêu thích của bạn.

+0

Thật hữu ích, cảm ơn! –

6

Tôi đồng ý withe Cheeso. System.IO.Packaging là khó xử khi xử lý các tệp zip chung, xem như nó được thiết kế cho các tài liệu Office Open XML. Tôi khuyên bạn nên sử dụng DotNetZip hoặc SharpZipLib

12

Tôi gặp vấn đề tương tự! Để có được phương thức GetParts() trả về một cái gì đó, tôi phải thêm tệp [Content_Types] .xml vào thư mục gốc của tệp lưu trữ bằng nút "Mặc định" cho mọi phần mở rộng tệp được bao gồm. Một khi tôi đã thêm điều này (chỉ cần sử dụng Windows Explorer), mã của tôi đã có thể đọc và trích xuất các nội dung đã lưu trữ.

Thông tin thêm về [Content_Types] tập tin .xml có thể được tìm thấy ở đây:

http://msdn.microsoft.com/en-us/magazine/cc163372.aspx - Có một tập tin ví dụ dưới đây Hình 13 bài viết.

var zipFilePath = "c:\\myfile.zip"; 
var tempFolderPath = "c:\\unzipped"; 

using (Package package = ZipPackage.Open(zipFilePath, FileMode.Open, FileAccess.Read)) 
{ 
    foreach (PackagePart part in package.GetParts()) 
    { 
     var target = Path.GetFullPath(Path.Combine(tempFolderPath, part.Uri.OriginalString.TrimStart('/'))); 
     var targetDir = target.Remove(target.LastIndexOf('\\')); 

     if (!Directory.Exists(targetDir)) 
      Directory.CreateDirectory(targetDir); 

     using (Stream source = part.GetStream(FileMode.Open, FileAccess.Read)) 
     { 
      FileStream targetFile = File.OpenWrite(target); 
      source.CopyTo(targetFile); 
      targetFile.Close(); 
     } 
    } 
} 

Lưu ý: mã này sử dụng phương pháp Stream.CopyTo trong .NET 4.0

+1

Cảm ơn bạn đã trả lời câu hỏi theo cách được hỏi! – shytikov

1

(Điều này về cơ bản là một rephrasing của this answer)

Hóa ra rằng System.IO.Packaging.ZipPackage không hỗ trợ PKZIP, đó là lý do tại sao khi bạn mở một tập tin ZIP "chung" không có "phần" được trả về. Lớp này chỉ hỗ trợ một số hương vị cụ thể của tệp ZIP (xem nhận xét ở dưới cùng của MSDN description) được sử dụng trong số các gói dịch vụ Windows Azure tối đa SDK 1.6 - đó là lý do tại sao nếu bạn giải nén gói dịch vụ và sau đó đóng gói lại bằng trình đóng gói Info-ZIP nó sẽ trở thành không hợp lệ.

Các vấn đề liên quan