4

There's a strange problem with DotNetZip that I can't seem to find a solution to. I've searched for a few hours now and I just can't find anything on this, so here goes.

var ms = new MemoryStream();
using (var archive = new Ionic.Zip.ZipFile()) {
    foreach (var file in files) {
        //                                string     byte[]
        var entry = archive.AddEntry(file.Name, file.Data);
        entry.ModifiedTime = DateTime.Now.AddYears(10); // Just for testing
    }
    archive.Save(ms);
}
return ms.GetBuffer();

I need to add the modified time, which is rather crucial, but right now I just have a dummy timestamp.

When I open the file with WinRAR, it says "Unexpected end of archive". Each individual file has checksum 00000000, and WinRAR says "The archive is either in unknown format or damaged". I can repair it, which brings it down 20% in size and makes everything OK. But that's not really useful..

When I make a breakpoint after adding all the entries, I can see in zip.Entries that all the entries have that same bad CRC, but all the data seems to be there. So it shouldn't be the way I save the archive that's the problem.

I use my file collection elsewhere without problems, which adds to DotNetZip being weird. Well either that or I misunderstand something :)

Heki
  • 926
  • 2
  • 15
  • 34
  • 2
    `GetBuffer` is certainly wrong, since the buffer is often bigger than the content. Use `ToArray()`. Or carefully handle the incompletely filled buffer in the consuming code. – CodesInChaos Apr 24 '12 at 06:59
  • I'm glad we got that out of the way. It actually solved the problem. Can you add that comment as answer so I can accept it as such? – Heki Apr 24 '12 at 07:06

1 Answers1

6

GetBuffer is certainly wrong. It returns the internal buffer of the MemoryStream, which is often bigger than the actual content.

To return an array that only contains the actual content, use ToArray().

Or you could carefully handle the incompletely filled buffer in the consuming code. This would reduce GC pressure, since you don't need to allocate a whole new array for the return value.

If the zip-archive is large, I'd also consider saving to a file directly, instead of assembling the archive in-memory.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • Thanks, CodeInChaos. You have some good points here. Handeling of the buffer would be to remove all trailing 0 bytes? – Heki Apr 24 '12 at 07:17
  • 1
    That depends on the calling code. It'll amount to passing around the length of the valid data, and treating it appropriately. You can't consider all trailing `0` bytes invalid, only those beyond `ms.Length`. – CodesInChaos Apr 24 '12 at 07:27