ZIP file created with SharpZipLib cannot be opened on Mac OS X

前端 未结 10 1313
有刺的猬
有刺的猬 2021-02-04 08:31

Argh, today is the day of stupid problems and me being an idiot.

I have an application which creates a zip file containing some JPEGs from a certain directory. I use th

相关标签:
10条回答
  • 2021-02-04 09:22

    I had exactly the same problem, my mistake was (and in your example code as well) that I didn't supply the file lenght for each entry.

    Example code:

     ...
     ZipEntry entry = new ZipEntry(Path.GetFileName(pathname));
     entry.DateTime = now;
     var fileInfo = new FileInfo(pathname)
     entry.size  = fileInfo.lenght;
     ...
    
    0 讨论(0)
  • 2021-02-04 09:23

    I agree with Cheeso's answer however if the Input file size is greater than 2GB then byte[] buffer = File.ReadAllBytes(pathname); will throw an IO exception. So i modified Cheeso code and it works like a charm for all the files.

    .

           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();
    
                }
            }
    
    0 讨论(0)
  • 2021-02-04 09:33

    I don't know for sure, because I am not very familiar with either SharpZipLib or OSX , but I still might have some useful insight for you.

    I've spent some time wading through the zip spec, and actually I wrote DotNetZip, which is a zip library for .NET, unrelated to SharpZipLib.

    Currently on the user forums for DotNetZip, there's a discussion going on about zip files generated by DotNetZip that cannot be read on OSX. One of the people using the library is having a problem that seems similar to what you are seeing. Except I have no idea what a .cpgxz file is.

    We tracked it down, a little. At this point the most promising theory is that OSX does not like "bit 3" in the "general purpose bitfield" in the header of each zip entry.

    Bit 3 is not new. PKWare added bit 3 to the spec 17 years ago. It was intended to support streaming generation of archives, in the way that SharpZipLib works. DotNetZip also has a way to produce a zipfile as it is streamed out, and it will also set bit-3 in the zip file if used in this way, although normally DotNetZip will produce a zipfile with bit-3 unset in it.

    From what we can tell, when bit 3 is set, the OSX zip reader (whatever it is - like I said I'm not familiar with OSX) chokes on the zip file. The same zip contents produced without bit 3, allows the zip file to be opened. Actually it's not as simple as just flipping one bit - the presence of the bit signals the presence of other metadata. So I am using "bit 3" as a shorthand for all that.

    So the theory is that bit 3 causes the problem. I haven't tested this myself. There's been some impedance mismatch on the communication with the person who has the OSX machine - so it is unresolved as yet.

    But, if this theory holds, it would explain your situation: that WinRar and any Windows machine can open the file, but OSX cannot.

    On the DotNetZip forums, we had a discussion about what to do about the problem. As near as I can tell, the OSX zip reader is broken, and cannot handle bit 3, so the workaround is to produce a zip file with bit 3 unset. I don't know if SharpZipLib can be convinced to do that.

    I do know that if you use DotNetZip, and use the normal ZipFile class, and save to a seekable stream (like a filesystem file), you will get a zip that does not have bit 3 set. If the theory is correct, it should open with no problem on the Mac, every time. This is the result the DotNetZip user has reported. It's just one result so not generalizable yet, but it looks plausible.

    example code for your scenario:

      using (ZipFile zip = new ZipFile()
      {
          zip.AddFiles(pathnames);
          zip.Save("Out2.zip");
      }
    

    Just for the curious, in DotNetZip you will get bit 3 set if you use the ZipFile class and save it to a nonseekable stream (like ASPNET's Response.OutputStream) or if you use the ZipOutputStream class in DotNetZip, which always writes forward only (no seeking back). I think SharpZipLib's ZipOutputStream is also always "forward only."

    0 讨论(0)
  • 2021-02-04 09:35

    I was separating the folder names with a backslash... when I changed this to a forward slash it worked!

    0 讨论(0)
提交回复
热议问题