49

我有一堆急需进行分层重组和提取的 ZIP 文件。目前,我可以做的是创建目录结构并将 zip 文件移动到正确的位置。我缺少的神秘奶酪是从 ZIP 存档中提取文件的部分。

我在ZipArchive课堂上看过 MSDN 文章,并且对它们理解得很好。我还看到了VBScript 提取. 这不是一个复杂的类,因此提取内容应该非常简单。事实上,它“大部分”都有效。我在下面包含了我当前的代码以供参考。

 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.
    }
 }

问题似乎出在某个地方GetParts(或就此而言获得任何东西)。似乎打开的包裹是空的。深入挖掘调试器显示私有成员 _zipArchive 表明它实际上有部分。具有正确名称的零件和所有内容。为什么函数不会GetParts检索它们?我曾尝试将开放投射到 ZipArchive 并没有帮助。嗯。

4

6 回答 6

47

如果您正在处理 ZIP 文件,您可能需要查看第 3 方库来帮助您。

例如最近更新的 DotNetZip。当前版本现在是 v1.8。以下是创建 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");
}

这是一个更新现有 zip的示例;您无需提取文件即可:

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

这是一个提取条目的示例:

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

DotNetZip 支持文件名中的多字节字符、Zip 加密、AES 加密、流、Unicode、自解压档案。ZIP64 也适用于大于 0xFFFFFFFF 的文件长度,或具有超过 65535 个条目的档案。

自由。开源

在codeplex获取它 或从 windows.net 直接下载- CodePlex 已停产并存档

于 2009-02-10T06:09:38.180 回答
46

来自MSDN

在此示例中,使用了 Package 类(与 ZipPackage 相对)。在使用了这两种方法后,我只看到 zip 文件损坏时会出现片状问题。不一定是引发 Windows 提取程序或 Winzip 的损坏,而是打包组件无法处理的问题。

希望这会有所帮助,也许它可以为您提供调试问题的替代方法。

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();
    }
}
于 2009-02-03T17:21:09.963 回答
31

来自“ ZipPackage 类”(MSDN):

虽然包通过 ZipPackage 类存储为 Zip 文件*,但所有 Zip 文件都不是 ZipPackage。ZipPackage 具有特殊要求,例如符合 URI 的文件(部分)名称和定义包中包含的所有文件的 MIME 类型的“[Content_Types].xml”文件。ZipPackage 类不能用于打开不符合 Open Packaging Conventions 标准的任意 Zip 文件。

有关详细信息,请参阅 ECMA 国际“开放包装约定”标准的第 9.2 节“映射到 ZIP 存档”,http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML% 20Part%202%20(DOCX).zip (342Kb) 或http://www.ecma-international.org/publications/files/ECMA-ST/Office%20Open%20XML%20Part%202%20(PDF).zip (1.3Mb)

*您只需将“.zip”添加到任何基于 ZipPackage 的文件(.docx、.xlsx、.pptx 等)的扩展名中,即可在您最喜欢的 Zip 实用程序中打开它。

于 2009-02-03T17:34:15.473 回答
13

我遇到了完全相同的问题!为了让 GetParts() 方法返回某些内容,我必须将 [Content_Types].xml 文件添加到存档的根目录,并为包含的每个文件扩展名添加一个“默认”节点。一旦我添加了这个(仅使用 Windows 资源管理器),我的代码就能够读取和提取存档内容。

有关 [Content_Types].xml 文件的更多信息,请参见此处:

http://msdn.microsoft.com/en-us/magazine/cc163372.aspx - 在文章的图 13 下方有一个示例文件。

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

注意:此代码使用 .NET 4.0 中的 Stream.CopyTo 方法

于 2012-04-09T12:01:35.523 回答
6

我同意奶酪。System.IO.Packaging 在处理通用 zip 文件时很尴尬,因为它是为 Office Open XML 文档设计的。我建议使用DotNetZipSharpZipLib

于 2009-02-10T06:51:13.680 回答
2

(这基本上是这个答案的改写)

原来System.IO.Packaging.ZipPackage它不支持 PKZIP,这就是为什么当你打开一个“通用”ZIP 文件时没有返回“部分”。此类仅支持某些特定风格的 ZIP 文件(请参阅MSDN 描述底部的注释),在 SDK 1.6 之前用作 Windows Azure 服务包 - 这就是为什么如果您解压缩服务包然后使用 Info-ZIP 重新打包它的原因打包程序将变为无效。

于 2012-08-21T08:34:49.190 回答