Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# .NET Why Stream.Seek is required when unzipping stream

I'm working on a project where I need the ability to unzip streams and byte arrays as well as zip them. I was running some unit tests that create the Zip from a stream and then unzip them and when I unzip them, the only way that DonNetZip sees them as a zip is if I run streamToZip.Seek(o,SeekOrigin.Begin) and streamToZip.Flush(). If I don't do this, I get the error "Cannot read Block, No data" on the ZipFile.Read(stream).

I was wondering if anyone could explain why that is. I've seen a few articles on using it to actually set the relative read position, but none that really explain why in this situation it is required.

Here is my Code:

Zipping the Object:

   public Stream ZipObject(Stream data)
    {
        var output = new MemoryStream();
        using (var zip = new ZipFile())
        {
            zip.AddEntry(Name, data);
            zip.Save(output);
            FlushStream(output);
            ZippedItem = output;
        }

        return output;
    }

Unzipping the Object:

 public List<Stream> UnZipObject(Stream data)
    {
        ***FlushStream(data); // This is what I had to add in to make it work***

        using (var zip = ZipFile.Read(data))
        {
            foreach (var item in zip)
            {
                var newStream = new MemoryStream();
                item.Extract(newStream);
                UnZippedItems.Add(newStream);
            }
        }
        return UnZippedItems;
    }

Flush method I had to add:

    private static void FlushStream(Stream stream)
    {
        stream.Seek(0, SeekOrigin.Begin);
        stream.Flush();
    }
like image 853
gcoleman0828 Avatar asked Dec 20 '22 23:12

gcoleman0828


1 Answers

When you return output from ZipObject, that stream is at the end - you've just written the data. You need to "rewind" it so that the data can then be read. Imagine you had a video cassette, and had just recorded a program - you'd need to rewind it before you watched it, right? It's exactly the same here.

I would suggest doing this in ZipObject itself though - and I don't believe the Flush call is necessary. I'd personally use the Position property, too:

public Stream ZipObject(Stream data)
{
    var output = new MemoryStream();
    using (var zip = new ZipFile())
    {
        zip.AddEntry(Name, data);
        zip.Save(output);
    }
    output.Position = 0;
    return output;
}
like image 53
Jon Skeet Avatar answered Feb 15 '23 22:02

Jon Skeet