使用SharpZipLib创建的ZIP文件无法在Mac OS X上打开

Max*_*Max 13 c# macos zip

唉,今天是愚蠢问题的日子,我是个白痴.

我有一个应用程序,它创建一个zip文件,其中包含某个目录中的一些JPEG.我使用此代码以便:

  • 从目录中读取所有文件
  • 将它们中的每一个附加到ZIP文件中

using (var outStream = new FileStream("Out2.zip", FileMode.Create))
{
    using (var zipStream = new ZipOutputStream(outStream))
    {
        foreach (string pathname in pathnames)
        {
            byte[] buffer = File.ReadAllBytes(pathname);

            ZipEntry entry = new ZipEntry(Path.GetFileName(pathname));
            entry.DateTime = now;

            zipStream.PutNextEntry(entry);
            zipStream.Write(buffer, 0, buffer.Length);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一切都在Windows下运行良好,当我打开文件,例如使用WinRAR,文件被提取.但是当我尝试在Mac OS X上解压缩我的存档时,它只会创建一个.cpgz文件.相当无用.

.zip在Windows和Mac OS X上提取在Windows上使用相同文件手动创建的普通文件,没有任何问题.

我在互联网上找到了上面的代码,所以我不确定整件事情是否正确.我想知道是否需要使用zipStream.Write()才能直接写入流?

Che*_*eso 16

我不确定,因为我对SharpZipLib或OSX都不是很熟悉,但我仍然可以为你提供一些有用的见解.

我花了一些时间浏览zip规范,实际上我写了DotNetZip,这是一个.NET的zip库,与SharpZipLib无关.

目前在DotNetZip的用户论坛上,正在讨论由DotNetZip生成的无法在OSX上读取的zip文件.其中一个使用该库的人遇到的问题与您所看到的类似.除了我不知道.cpgxz文件是什么.

我们跟踪了一下.此时最有希望的理论是OSX不喜欢每个zip条目标题中"通用位域"中的"位3".

第3位并不新鲜.PKWare在17年前为该规范添加了第3位.它旨在以SharpZipLib的工作方式支持流式媒体生成.DotNetZip也有办法产生的压缩文件,因为它是流出来的,如果采用这种方式,虽然通常DotNetZip将产生位3 zip文件也将设置位3在zip文件中未设置它.

从我们可以看出,当第3位设置时,OSX zip阅读器(无论是什么 - 就像我说我不熟悉OSX)在zip文件上窒息.没有第3位产生的相同压缩内容允许打开zip文件.实际上它并不像只是翻转一位那么简单 - 位的存在表明存在其他元数据.所以我使用"第3位"作为所有这些的简写.

所以理论是第3位引起了问题.我自己没有测试过.与拥有OSX机器的人的通信存在一些阻抗不匹配 - 因此尚未解决.

但是,如果这个理论成立,它可以解释你的情况:WinRar和任何Windows机器都可以打开文件,但OSX不能.

在DotNetZip论坛上,我们讨论了如何解决这个问题.尽管我可以说,OSX zip阅读器坏了,无法处理第3位,因此解决方法是生成一个未设置位3的zip文件.我不知道是否可以说服SharpZipLib这样做.

我知道,如果你使用DotNetZip,并使用正常的ZipFile类,并保存到可搜索的数据流(如文件系统文件),你会得到不具有3位集的拉链.如果理论是正确的,那么每次都应该在Mac上打开没有任何问题.这是DotNetZip用户报告的结果.这只是一个结果,所以还没有推广,但看起来似乎有道理.

您的方案的示例代码:

  using (ZipFile zip = new ZipFile()
  {
      zip.AddFiles(pathnames);
      zip.Save("Out2.zip");
  }
Run Code Online (Sandbox Code Playgroud)

只是为了好奇,在DotNetZip中,如果你使用ZipFile类并将其保存到一个不可搜索的流(如ASPNET的Response.OutputStream),或者如果你在DotNetZip中使用ZipOutputStream类,那么你将获得第3位设置,它总是只向前写入(不寻求回来).我认为SharpZipLib的ZipOutputStream也总是"向前发展".


小智 15

今天遇到了完全相同的问题.我试图按照提议实现CRC的东西,但它没有帮助.

我最终在这个页面上找到了解决方案:http://community.sharpdevelop.net/forums/p/7957/23476.aspx#23476

因此,我只需在我的代码中添加以下行:

oZIPStream.UseZip64 = UseZip64.Off;

并且该文件在MacOS X上应该打开:-)

干杯弗雷德


Max*_*Max 13

所以,我搜索了一些关于如何使用SharpZipLib的例子,我终于让它在Windows和os x上运行了.基本上我将文件的"Crc32"添加到zip存档中.不知道这是什么.

这是适合我的代码:

        using (var outStream = new FileStream("Out3.zip", FileMode.Create))
        {
            using (var zipStream = new ZipOutputStream(outStream))
            {
                Crc32 crc = new Crc32();

                foreach (string pathname in pathnames)
                {
                    byte[] buffer = File.ReadAllBytes(pathname);

                    ZipEntry entry = new ZipEntry(Path.GetFileName(pathname));
                    entry.DateTime = now;
                    entry.Size = buffer.Length;

                    crc.Reset();
                    crc.Update(buffer);

                    entry.Crc = crc.Value;

                    zipStream.PutNextEntry(entry);
                    zipStream.Write(buffer, 0, buffer.Length);
                }

                zipStream.Finish();

                // I dont think this is required at all
                zipStream.Flush();
                zipStream.Close();

            }
        }
Run Code Online (Sandbox Code Playgroud)

来自cheeso的解释:

CRC是循环冗余校验 - 它是条目数据的校验和.通常,zip文件中每个条目的标题包含一堆元数据,包括在流式传输所有条目数据之前无法知道的一些内容 - CRC,未压缩大小和压缩大小.通过流输出生成zipfile时,zip规范允许设置一个位(第3位)以指定这三个数据字段将紧跟在条目数据之后.

如果使用ZipOutputStream,通常在写入条目数据时,会对其进行压缩并计算CRC,并在文件数据之后立即写入3个数据字段.

您所做的是将数据流式传输两次 - 第一次隐式地在您编写文件之前计算文件上的CRC.如果我的理论是正确的,那么正在发生的事情是:当你在写入文件数据之前向zipStream提供CRC时,这允许CRC出现在条目头中的正常位置,这使OSX保持高兴.我不确定其他两个量(压缩和未压缩的大小)会发生什么.