使用C#和System.IO.Packaging以编程方式从Zip存档中提取文件

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

我已经看过有关GetParts类的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(或与此有关的GetAnything)中。 似乎该包装在打开时是空的。 对调试器进行更深入的研究表明,私有成员_zipArchive表明它实际上具有部分内容。 具有正确名称和所有内容的零件。 为什么GetParts函数无法检索它们? 我曾经尝试过向ZipArchive公开投票,但这没有帮助。 rr

Craig asked 2020-02-29T09:57:16Z
6个解决方案
47 votes

如果要处理ZIP文件,则可能需要研究第三方库来帮助您。

例如,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已停产并存档

Cheeso answered 2020-02-29T09:57:54Z
44 votes

从MSDN,

在此示例中,使用了Package类(与ZipPackage相对。)两者都使用过,我只看到zip文件损坏时会发生晃动。 不一定抛出Windows提取程序或Winzip的损坏,而是Packaging组件无法处理的某些损坏。

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

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();
    }
}
jro answered 2020-02-29T09:58:23Z
31 votes

来自“ ZipPackage类”(MSDN):

虽然通过ZipPackage类将程序包存储为Zip文件*,但所有Zip文件都不是ZipPackages。 ZipPackage具有特殊要求,例如符合URI的文件(部分)名称和“ [Content_Types] .xml”文件,该文件定义Package中包含的所有文件的MIME类型。 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)

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

Luke answered 2020-02-29T09:59:04Z
13 votes

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

有关[Content_Types] .xml文件的更多信息,可以在这里找到:

[http://msdn.microsoft.com/zh-cn/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方法

Joshua answered 2020-02-29T09:59:38Z
6 votes

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

Rad answered 2020-02-29T09:59:58Z
1 votes

(这基本上是该答案的措辞)

原来System.IO.Packaging.ZipPackage不支持PKZIP,这就是为什么当您打开“通用” ZIP文件时不会返回“部件”的原因。 此类仅支持某些特定种类的ZIP文件(请参阅MSDN描述的底部的注释),以及直到SDK 1.6为止都用作Windows Azure服务包的正则表达式-这就是为什么要解压服务包,然后使用Info-ZIP重新打包的原因 加壳程序将变得无效。

sharptooth answered 2020-02-29T10:00:24Z
translate from https://stackoverflow.com:/questions/507751/extracting-files-from-a-zip-archive-programmatically-using-c-sharp-and-system-io