Search code examples
c#dotnetzip

DotNetZip - Cannot access a closed Stream


None of the similar questions are quite what I'm looking for!

What's wrong with the following code? files is a text array of file contents, and fileNames is the corresponding filename array.

This code always fails at the second-last line with the Save method, but I can't see why the stream would be closed!

result = new MemoryStream();

using (ZipFile zipFile = new ZipFile())
{
    for (int i = 0; i < files.Count(); i++)
    {
        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
        Byte[] bytes = encoding.GetBytes(files[i]);
        using (MemoryStream fs = new MemoryStream(bytes))
        {
            zipFile.AddEntry(fileNames[i], fs);
        }
    }
    zipFile.Save(result);
}

Thanks for any help - getting desperate here!

This is my solution based on @spender's first comment, although his solution posted below is possibly nicer.

        try
        {
            result = new MemoryStream();
            List<Stream> streams = new List<Stream>();

            if (files.Count > 0)
            {
                using (ZipFile zipFile = new ZipFile())
                {
                    for (int i = 0; i < files.Count(); i++)
                    {

                        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                        Byte[] bytes = encoding.GetBytes(files[i]);
                        streams.Add(new MemoryStream(bytes));
                        zipFile.AddEntry(fileNames[i], streams[i]);
                    }
                    zipFile.Save(result);
                }
            }
        }
        catch (Exception ex)
        {
            throw;
        }

Solution

  • It seems that calling Save is the point when the source streams are read. This means you have to keep them undisposed until after the save. Abandon using statement in this case as it is impossible to extend its scope beyond the loop. Instead, collect your IDisposables and dispose of them once the save is completed.

    result = new MemoryStream();
    
    using (ZipFile zipFile = new ZipFile())
    {
        List<IDisposable> memStreams = new List<IDisposable>();
        try
        {
            for (int i = 0; i < files.Count(); i++)
            {
                System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                Byte[] bytes = encoding.GetBytes(files[i]);
                MemoryStream fs = new MemoryStream(bytes);
                zipFile.AddEntry(fileNames[i], fs);
                memStreams.Add(fs);
            }
            zipFile.Save(result);
        }
        finally
        {
            foreach(var x in memStreams)
            {
                x.Dispose();
            }
        }
    }