C# 无法在Mac OS X上打开使用SharpZipLib创建的ZIP文件
啊,今天是愚蠢问题的日子,我是个白痴 我有一个应用程序,它创建了一个zip文件,其中包含来自某个目录的一些jpeg。我使用此代码是为了:C# 无法在Mac OS X上打开使用SharpZipLib创建的ZIP文件,c#,macos,zip,C#,Macos,Zip,啊,今天是愚蠢问题的日子,我是个白痴 我有一个应用程序,它创建了一个zip文件,其中包含来自某个目录的一些jpeg。我使用此代码是为了: 从目录中读取所有文件 将它们中的每一个附加到ZIP文件 当我打开文件e时,所有这些在Windows下都能正常工作。G使用,将提取文件。但当我试图在Mac OS X上解压我的归档文件时,它只会创建一个.cpgz文件。真没用 正常的.zip文件在Windows上使用相同的文件手动创建,在Windows和Mac OS X上提取时不会出现任何问题 我在网上找到了
- 从目录中读取所有文件
- 将它们中的每一个附加到ZIP文件
当我打开文件e时,所有这些在Windows下都能正常工作。G使用,将提取文件。但当我试图在Mac OS X上解压我的归档文件时,它只会创建一个
.cpgz
文件。真没用
正常的.zip
文件在Windows上使用相同的文件手动创建,在Windows和Mac OS X上提取时不会出现任何问题
我在网上找到了上面的代码,所以我不能完全确定整个代码是否正确。我想知道是否需要使用
zipStream.Write()
,以便直接写入流?我不确定,因为我对SharpZipLib或OSX都不是很熟悉,但我仍然可能对您有一些有用的见解
我花了一些时间研究了zip规范,实际上我写了一个.NET的zip库,与SharpZipLib无关
目前在DotNetZip的用户论坛上,有一个关于DotNetZip生成的无法在OSX上读取的zip文件的讨论正在进行。使用图书馆的人中有一个人遇到了一个与您所看到的问题相似的问题。除了我不知道.cpgxz文件是什么
我们查了一下。在这一点上,最有希望的理论是OSX不喜欢每个zip条目标题中“通用位字段”中的“第3位”
第3位不是新的。17年前,PKWare在规范中增加了第3位。它旨在以SharpZipLib的工作方式支持档案的流式生成。DotNetZip还有一种方法可以在流式输出时生成zipfile,如果以这种方式使用,它还将在zip文件中设置位3,尽管通常DotNetZip会生成位3未设置的zipfile
从我们可以看出,当设置位3时,OSX zip阅读器(不管它是什么-就像我说的我不熟悉OSX)会阻塞zip文件。不使用第3位生成的相同zip内容允许打开zip文件。实际上,这并不像翻转一个位那么简单——该位的存在表示其他元数据的存在。所以我用“比特3”作为所有这些的简写
因此,理论是第3位导致了问题。我自己还没有测试过。与拥有OSX机器的人的通信中出现了一些阻抗不匹配的情况,因此目前尚未解决
但是,如果这个理论成立,它可以解释你的情况:WinRar和任何Windows机器都可以打开文件,但OSX不能
在DotNetZip论坛上,我们讨论了如何解决这个问题。据我所知,OSX zip阅读器已损坏,无法处理位3,因此解决方法是生成一个未设置位3的zip文件。我不知道SharpZipLib是否能被说服这么做
我确实知道,如果您使用DotNetZip,使用普通的ZipFile类,并保存到可查找的流(如文件系统文件),您将得到一个未设置位3的zip。如果理论是正确的,它应该在Mac上打开,每次都没有问题。这是DotNetZip用户报告的结果。这只是一个结果,所以还不能概括,但它看起来似乎有道理
场景的示例代码:
using (ZipFile zip = new ZipFile()
{
zip.AddFiles(pathnames);
zip.Save("Out2.zip");
}
出于好奇,在DotNetZip中,如果您使用ZipFile类并将其保存到不可查找的流(如ASPNET的Response.OutputStream),或者如果您在DotNetZip中使用zipoutpstream类,则会设置第3位,该类始终只向前写入(不返回)。
我认为SharpZipLib的ZipoutStream也总是“只向前”的。因此,我搜索了更多关于如何使用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();
}
}
cheeso的解释: CRC是循环冗余校验-它是对输入数据的校验和。通常,zip文件中每个条目的标题都包含一组元数据,包括一些在所有条目数据流化之前无法知道的内容—CRC、未压缩大小和压缩大小。当通过流式输出生成zipfile时,zip规范允许设置一个位(位3),以指定这三个数据字段将立即跟随输入数据 如果使用ZipoutStream,通常在写入条目数据时,会对其进行压缩并计算CRC,并且会在文件数据之后立即写入3个数据字段 您所做的是将数据流传输两次,第一次是在写入文件之前隐式计算文件的CRC。如果我的理论是正确的,发生的事情是这样的:当您在写入文件数据之前向zipStream提供CRC时,这允许CRC显示在条目头中的正常位置,这使OSX感到高兴。我不确定其他两个量(压缩大小和未压缩大小)会发生什么变化
使用
.cpgz
文件的原因是存档实用程序是由扩展名为.zip
的文件启动的。存档实用程序检查文件并认为它没有被压缩,所以它正在压缩它。出于某种奇怪的原因,.cpgz
(CPIO存档+gzip压缩)是默认设置。您可以在Archive Utility的首选项中设置不同的默认值
如果您确实发现OSX的zip解码器存在问题,请提交一份文件。您还可以尝试使用同上
命令行工具将其解包;您可能会收到更好的错误消息。当然,OSX也提供了unzip
,信息压缩实用程序,但我希望它能起作用。<
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();
}
}
long maxDataToBuffer = 104857600;//100MB
using (var outStream = new FileStream("Out3.zip", FileMode.Create))
{
using (var zipStream = new ZipOutputStream(outStream))
{
Crc32 crc = new Crc32();
foreach (string pathname in pathnames)
{
tempBuffLength = maxDataToBuffer;
FileStream fs = System.IO.File.OpenRead(pathname);
ZipEntry entry = new ZipEntry(Path.GetFileName(pathname));
entry.DateTime = now;
entry.Size = buffer.Length;
crc.Reset();
long totalBuffLength = 0;
if (fs.Length <= tempBuffLength) tempBuffLength = fs.Length;
byte[] buffer = null;
while (totalBuffLength < fs.Length)
{
if ((fs.Length - totalBuffLength) <= tempBuffLength)
tempBuffLength = (fs.Length - totalBuffLength);
totalBuffLength += tempBuffLength;
buffer = new byte[tempBuffLength];
fs.Read(buffer, 0, buffer.Length);
crc.Update(buffer, 0, buffer.Length);
buffer = null;
}
entry.Crc = crc.Value;
zipStream.PutNextEntry(entry);
tempBuffLength = maxDataToBuffer;
fs = System.IO.File.OpenRead(pathname);
totalBuffLength = 0;
if (fs.Length <= tempBuffLength) tempBuffLength = fs.Length;
buffer = null;
while (totalBuffLength < fs.Length)
{
if ((fs.Length - totalBuffLength) <= tempBuffLength)
tempBuffLength = (fs.Length - totalBuffLength);
totalBuffLength += tempBuffLength;
buffer = new byte[tempBuffLength];
fs.Read(buffer, 0, buffer.Length);
zipStream.Write(buffer, 0, buffer.Length);
buffer = null;
}
fs.Close();
}
zipStream.Finish();
// I dont think this is required at all
zipStream.Flush();
zipStream.Close();
}
}
...
ZipEntry entry = new ZipEntry(Path.GetFileName(pathname));
entry.DateTime = now;
var fileInfo = new FileInfo(pathname)
entry.size = fileInfo.lenght;
...
entry.Crc = crc.Value