Save ZipFile to MemoryStream, but then the MemoryStream is not readable

Feb 29, 2008 at 8:30 PM
Hello, wonderful library you have here.

I am trying to construct a zip file and save it to a MemoryStream on a server. The server will then pass the MemoryStream to a client that will write the MemoryStream to disk. It seems to me that when ZipFile.Save( ) is called, the MemoryStream is no longer readable. This makes the MemoryStream output pretty useless. Am I missing something? Here is a code example of what I am trying to do:

MemoryStream stream = new MemoryStream( );

ZipFile zip = new ZipFile(stream);

zip.AddFile("C:\\InputFile1.txt");
zip.AddFile("C:\\InputFile2.txt");

zip.Save( );

After calling zip.Save( ), the "CanRead", "CanWrite" and "CanSeek" properties on the MemoryStream are all set to false. The "Capacity", "Length" and "Position" properties all give a System.ObjectDisposedException when viewed in the watch window. Is the MemoryStream being disposed when ZipFile.Save( ) is called? Am I just overlooking something simple? Thanks for your response.
Feb 29, 2008 at 10:17 PM
After looking at the source code, it appears that the ZipFile.Save( ) method calls Close( ) on the output stream that was passed to the constructor and sets it to null. My question is, why have output stream support in the constructor if you are just going to discard the output stream immediately after writing to it? It seems pointless unless I am missing something.
Feb 29, 2008 at 10:57 PM
Here is my modification to the ZipFile.Save( ) method:

public void Save()
{
// check if modified, before saving.
if (!_contentsChanged) return;

if (Verbose) StatusMessageTextWriter.WriteLine("Saving....");

// an entry for each file
foreach (ZipEntry e in _entries)
{
e.Write(WriteStream);
}

WriteCentralDirectoryStructure();

// _temporaryFileName may remain null if we are writing to a stream
if (_temporaryFileName != null)
{
WriteStream.Close();
WriteStream = null;

if (_fileAlreadyExists)
System.IO.File.Replace(_temporaryFileName, _name, null);
else
System.IO.File.Move(_temporaryFileName, _name);
}

_fileAlreadyExists = true;
}

It shifts the responsibility for closing the output stream to the caller (where it should be). If there is a temp file name (no output stream provided) it behaves like it did before my modification. This seems to work for my purposes.
Feb 29, 2008 at 11:22 PM
It looks like Daniel Bedarf solved my problem with his changes which can be downloaded here:
http://www.codeplex.com/DotNetZip/WorkItem/View.aspx?WorkItemId=3640

Nice work Daniel. I needed that add entry from MemoryStream stuff as well.
Coordinator
Apr 3, 2008 at 9:05 PM


McFeely wrote:
It looks like Daniel Bedarf solved my problem with his changes which can be downloaded here:
http://www.codeplex.com/DotNetZip/WorkItem/View.aspx?WorkItemId=3640

Nice work Daniel. I needed that add entry from MemoryStream stuff as well.


McFeely, I like your changes and I like Daniel's changes too. I updated a change set with these today, see changeset 16336.
Thanks for the contributions!
Apr 15, 2008 at 6:42 PM
I'm hoping to get my hands on this latest update, however, in my project i'm just leveraging the .dll. Pardon my ignorance, but how do I get my hands on this change if I don't want to add the source code to my project? Is there another way? Is there a new .dll/release that will be published soon?

Thanks in advance and I LOVE this utility btw.
Coordinator
Apr 17, 2008 at 4:48 PM
Mikeandregan, you can grab the source and build it.
you need the .NET SDK to build.
Then add the resulting DLL into your project.

You don't have to add the source to your project. You can (and should) keep DotNetZip as a different project.