Adding entry from Stream is inserting a blank file

Apr 6, 2010 at 6:29 PM

Hello,

   I am needing to add an XML file to a ZIP archive.  The XML file is not stored on any file system, because it exists only as a character string in a database field.  I've been able to successfully pull the XML String out of the database and loaded it into a MemoryStream, but whenever I attempt to add a ZipEntry to my archive and use that MemoryStream as the source, my resultant archive contains a blank file.  I have tested, and if I write my XML out to the file system first, then perform a ZipFile.AddFile() call from the newly specified file, the archive is created as expected.  However, this is not acceptable in our production environment because only ZIP files and "FIN" files will be allowed to be written to disk.  Can anybody help explain why the MemoryStream isn't dumping to the archive?

 

MemoryStream stream = null;
command.CommandText = sql;
using (OracleDataReader reader = command.ExecuteReader())
{
   while (reader.Read())
   {
       payload = reader["Payload"].ToString();
       stream = new MemoryStream(payload.Length);
       StreamWriter writer = new StreamWriter(stream);
       writer.Write(payload);
       using (ZipFile zip = new ZipFile())
        {
            ZipEntry entry = zip.AddEntry("payload.xml", stream);
           //zip.AddFile("d:\\projects\\system\\Dashboard\\payload.xml");
           zip.AddFile("d:\\projects\\system\\Dashboard\\foo.txt");
           zip.Save("d:\\projects\\system\\Dashboard\\payload.zip");
         }
     }
}

Coordinator
Apr 6, 2010 at 7:24 PM

The reason your code is failing is that you have not called Seek() on the memory stream.  The Position of the MemoryStream after you have written it, is, by definition, at the end of the stream.  At this point you pass the stream as input for ZipFile.AddEntry().  At the time of ZipFile.Save(), DotNetZip attempts to read the stream.  Remember that the Position of the stream points to the end of the stream.  Therefore there is nothing to read.  If you call Seek(0,SeekOrigin.Begin), before calling ZipFile.AddEntry(), then it will work.

But, you don't need the stream.  Why not just use the ZipFile.AddEntry overload that accepts a string?

command.CommandText = sql;
using (OracleDataReader reader = command.ExecuteReader())
{
   while (reader.Read())
   {
       payload = reader["Payload"].ToString();
       using (ZipFile zip = new ZipFile())
        {
           zip.AddEntry("payload.xml", payload);
           zip.AddFile("d:\\projects\\system\\Dashboard\\foo.txt");
           zip.Save("d:\\projects\\system\\Dashboard\\payload.zip");
         }
     }
}
Apr 6, 2010 at 7:37 PM
Cheeso wrote:

But, you don't need the stream.  Why not just use the ZipFile.AddEntry overload that accepts a string?

...whoops lol.   ...I skimmed through the documentation and saw that it would accept a Stream in lieu of a file and jumped too hard into that. 

...and "oh yeah" about the MemoryStream.  I'd honestly completely forgotten that you have to 'reset' them like that (hadn't worked with a MemoryStream directly since probably my Sophomore year of school)