如何在C#中列出.zip文件夹的内容?

34

我该如何在C#中列出压缩文件夹的内容?例如,如何知道压缩文件夹中包含多少个项目以及它们的名称是什么?


1
如果使用的是.NET 4.5或更高版本,您就不再需要第三方库了!请查看下面的答案! - Csaba Toth
8个回答

40

.NET 4.5或更高版本终于具备了处理通用zip文件的内置功能,使用System.IO.Compression.ZipArchive类(http://msdn.microsoft.com/zh-cn/library/system.io.compression.ziparchive%28v=vs.110%29.aspx)在System.IO.Compression程序集中可实现。无需任何第三方库。

string zipPath = @"c:\example\start.zip";
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
        Console.WriteLine(entry.FullName);
    }
} 

6
无需第三方组件即可正常使用且开箱即用。请确保添加引用 System.IO.Compression.dllSystem.IO.Compression.FileSystem.dll - Matt

35

DotNetZip - .NET语言中的Zip文件操作。

DotNetZip是一个小巧、易于使用的类库,用于操纵.zip文件。它可以使VB.NET、C#或任何其他.NET语言编写的应用程序轻松创建、读取和更新zip文件。

读取zip文件的示例代码:

using (var zip = ZipFile.Read(PathToZipFolder))
{
    int totalEntries = zip.Entries.Count; 
    foreach (ZipEntry e in zip.Entries)
    {
        e.FileName ...
        e.CompressedSize ...
        e.LastModified...
    }
}

21

1
它消除了对外部库的依赖,但ZipPackage的可用性确实不是很好。一切都是权衡取舍! - Cheeso
ZipPackage 专门处理那些内部是 zip 文件的 Microsoft 相关文件格式,例如:docxxlsxXPSnupkg 等。从通用的 zip 文件角度来看,这些文件之间的区别仅在于存档根目录中放置了 Content_Type.xml 文件。如果您不能使用 .NET 4.5,但可以使用 .NET 3.0,则 ZipPackage 可以是完美的选择,只要您生成和使用这些文件即可。 - Csaba Toth
1
对于 .NET 4.5 或更高版本,应该使用 ZipArchive 类来进行通用的 zip 相关操作,请参见下面的答案。 - Csaba Toth

13

了解SharpZipLib

ZipInputStream inStream = new ZipInputStream(File.OpenRead(fileName));

while (inStream.GetNextEntry())
{

     ZipEntry entry = inStream.GetNextEntry();
     //write out your entry's filename
}

6

哎呀,那个使用J#运行时的代码太糟糕了!而且我不认为这是最好的方法 - J#现在已经停止支持了。如果你只想要ZIP支持,它还需要一个巨大的运行时。

那么这个怎么样 - 它使用的是DotNetZip(免费,MS-Public许可证)。

using (ZipFile zip = ZipFile.Read(zipfile) )
{
    bool header = true;
    foreach (ZipEntry e in zip)
    {
        if (header)
        {
            System.Console.WriteLine("Zipfile: {0}", zip.Name);
            if ((zip.Comment != null) && (zip.Comment != ""))
                System.Console.WriteLine("Comment: {0}", zip.Comment);

            System.Console.WriteLine("\n{1,-22} {2,9}  {3,5}   {4,9}  {5,3} {6,8} {0}",
                                     "Filename", "Modified", "Size", "Ratio", "Packed", "pw?", "CRC");
            System.Console.WriteLine(new System.String('-', 80));
            header = false;
        }

        System.Console.WriteLine("{1,-22} {2,9} {3,5:F0}%   {4,9}  {5,3} {6:X8} {0}",
                                 e.FileName,
                                 e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
                                 e.UncompressedSize,
                                 e.CompressionRatio,
                                 e.CompressedSize,
                                 (e.UsesEncryption) ? "Y" : "N",
                                 e.Crc32);

        if ((e.Comment != null) && (e.Comment != ""))
            System.Console.WriteLine("  Comment: {0}", e.Comment);
    }
}

4
如果你和我一样不想使用外部组件,这里提供了一些我昨晚开发的代码,使用了.NET的ZipPackage类。
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))
        {
            source.CopyTo(File.OpenWrite(target));
        }
    }
}

注意事项:

  • ZIP归档文件必须在其根目录中包含一个[Content_Types].xml文件。这对我的需求来说不是问题,因为我将控制通过此代码提取的任何ZIP文件的压缩。有关[Content_Types].xml文件的更多信息,请参见:一种打包数据的新标准,文章的图13下面有一个示例文件。

  • 此代码在.NET 4.0中使用了Stream.CopyTo方法。


1
MDSN杂志的哪个月和年份?https://msdn.microsoft.com/en-us/magazine/ee310108.aspx - Kiquenet

4

我在这里比较新,可能不太明白正在发生什么。:-) 当前有4个答案在这个帖子中,其中两个最好的答案已经被投票否决了。(pearcewg和cxfx的) pearcewg指向的文章很重要,因为它澄清了一些关于SharpZipLib许可问题的内容。 我们最近评估了几个.Net压缩库,并发现DotNetZip是目前最好的选择。

非常简短的总结:

  • System.IO.Packaging比DotNetZip慢得多。

  • SharpZipLib是GPL许可 - 请参阅文章。

所以首先,我支持这两个答案。

金。


1
GPL本身特别涉及到程序中不是“衍生自”GPL代码的部分,以及它们独立许可的权利。我不明白SharpZipLib采用GPL是一个重要问题。 - GalacticCowboy
2
GC,你是说如果一个团体或组织对GPL有问题,那么这个团体就是错的吗?还是说你根本无法理解为什么会有人对GPL有问题?这并不难以相信。媒体上充斥着昂贵法律测试的故事。 - Cheeso
3
是的,GPL有传染性。如果他正在开发商业闭源软件,并将他的代码链接到一个GPL许可的库中,那么他必须在GPL兼容许可下发布他的源代码。所以,SharpZibLib是GPL许可是一个重要问题。 - cdmckay
1
这篇文章是:对其他答案的评论;关于许可证的讨论(在任何情况下都很重要,但在这里并不是唯一的问题,也与问题无关);你投票的记录;以及一些库的推荐。它不是回答“如何在C#中列出.zip文件夹的内容?”这个问题。 - Stephen Kennedy

0

最好的方法是使用.NET内置的J# zip功能,如MSDN所示:http://msdn.microsoft.com/en-us/magazine/cc164129.aspx。在此链接中,有一个完整的工作示例,演示了读写zip文件的应用程序。对于列出zip文件内容的具体示例(在这种情况下是Silverlight .xap应用程序包),代码可能如下所示:


ZipFile package = new ZipFile(packagePath);
java.util.Enumeration entries = package.entries();
//We have to use Java enumerators because we
//use java.util.zip for reading the .zip files
while ( entries.hasMoreElements() )
{
    ZipEntry entry = (ZipEntry) entries.nextElement();

    if (!entry.isDirectory())
    {
        string name = entry.getName();
        Console.WriteLine("File: " + name + ", size: " + entry.getSize() + ", compressed size: " + entry.getCompressedSize());
    }
    else
    {
        // Handle directories...
    }                        
}

Aydsman 有一个正确的指针,但存在 问题。具体而言,您可能会遇到打开 zip 文件时的问题,但如果您打算仅创建包,则这是一个有效的解决方案。ZipPackage 实现了抽象 Package 类,并允许对 zip 文件进行操作。在 MSDN 中有一个如何执行此操作的示例:http://msdn.microsoft.com/en-us/library/ms771414.aspx。大致上,代码看起来像这样:
             string packageRelationshipType = @"http://schemas.microsoft.com/opc/2006/sample/document";
            string resourceRelationshipType = @"http://schemas.microsoft.com/opc/2006/sample/required-resource";
            // Open the Package.
            // ('using' statement insures that 'package' is
            //  closed and disposed when it goes out of scope.)
            foreach (string packagePath in downloadedFiles)
            {
                Logger.Warning("Analyzing " + packagePath);
                using (Package package = Package.Open(packagePath, FileMode.Open, FileAccess.Read))
                {
                    Logger.OutPut("package opened");
                    PackagePart documentPart = null;
                    PackagePart resourcePart = null;

                    // Get the Package Relationships and look for
                    //   the Document part based on the RelationshipType
                    Uri uriDocumentTarget = null;
                    foreach (PackageRelationship relationship in
                        package.GetRelationshipsByType(packageRelationshipType))
                    {
                        // Resolve the Relationship Target Uri
                        //   so the Document Part can be retrieved.
                        uriDocumentTarget = PackUriHelper.ResolvePartUri(
                            new Uri("/", UriKind.Relative), relationship.TargetUri);

                        // Open the Document Part, write the contents to a file.
                        documentPart = package.GetPart(uriDocumentTarget);
                        //ExtractPart(documentPart, targetDirectory);
                        string stringPart = documentPart.Uri.ToString().TrimStart('/');
                        Logger.OutPut("  Got: " + stringPart);
                    }

                    // Get the Document part's Relationships,
                    //   and look for required resources.
                    Uri uriResourceTarget = null;
                    foreach (PackageRelationship relationship in
                        documentPart.GetRelationshipsByType(
                                                resourceRelationshipType))
                    {
                        // Resolve the Relationship Target Uri
                        //   so the Resource Part can be retrieved.
                        uriResourceTarget = PackUriHelper.ResolvePartUri(
                            documentPart.Uri, relationship.TargetUri);

                        // Open the Resource Part and write the contents to a file.
                        resourcePart = package.GetPart(uriResourceTarget);

                        //ExtractPart(resourcePart, targetDirectory);
                        string stringPart = resourcePart.Uri.ToString().TrimStart('/');
                        Logger.OutPut("  Got: " + stringPart);
                    }

                }
            }

最好的方法似乎是使用J#,如MSDN所示:http://msdn.microsoft.com/en-us/magazine/cc164129.aspx

本文中还有指向更多C# .zip库的指针,这些库具有不同的许可证,例如SharpNetZip和DotNetZip:how to read files from uncompressed zip in c#?。由于许可证要求,它们可能不适合。


5
不,这不是最好的选择。J#运行时基于旧的Java库,其中的zip功能存在缺陷,并且已经停止支持。 - Cheeso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接