views:

4304

answers:

5

Is there a way to create a Zip archive that contains multiple files, when the files are currently in memory? The files I want to save are really just text only and are stored in a string class in my application. But I would like to save multiple files in a single self-contained archive. They can all be in the root of the archive.

It would be nice to be able to do this using SharpZipLib.

+2  A: 

Yes, you can use SharpZipLib to do this - when you need to supply a stream to write to, use a MemoryStream.

Jon Skeet
A: 

Use a StringReader to read from your string objects and expose them as Stream s.

That should make it easy to feed them to your zip-building code.

chakrit
+5  A: 

Use ZipEntry and PutNextEntry() for this. The following shows how to do it for a file, but for an in-memory object just use a MemoryStream

FileStream fZip = File.Create(compressedOutputFile);
ZipOutputStream zipOStream = new ZipOutputStream(fZip);
foreach (FileInfo fi in allfiles)
{
    ZipEntry entry = new ZipEntry((fi.Name));
    zipOStream.PutNextEntry(entry);
    FileStream fs = File.OpenRead(fi.FullName);
    try
    {
        byte[] transferBuffer[1024];
        do
        {
            bytesRead = fs.Read(transferBuffer, 0, transferBuffer.Length);
            zipOStream.Write(transferBuffer, 0, bytesRead);
        }
        while (bytesRead > 0);
    }
    finally
    {
        fs.Close();
    }
}
zipOStream.Finish();
zipOStream.Close();
Cory
Can you use 'using()' on the `zipOStream` instead of `Close()`?
Jay Bazuzi
Yes, ZipOutputStream is Disposable
Mike
+1  A: 

You could also do it a bit differently, using a Serializable object to store all strings

[Serializable]
public class MyStrings {
    public string Foo { get; set; }
    public string Bar { get; set; }
}

Then, you could serialize it into a stream to save it.
To save on space you could use GZipStream (From System.IO.Compression) to compress it. (note: GZip is stream compression, not an archive of multiple files).

That is, of course if what you need is actually to save data, and not zip a few files in a specific format for other software. Also, this would allow you to save many more types of data except strings.

configurator
I had kind of wanted to make the save file a format that would allow a user to open it up, and pull out specific pieces, but that may be the best/easiest thing to do...
Adam Haile
+6  A: 

Using SharpZipLib for this seems pretty complicated. This is so much easier in DotNetZip. In v1.9, the code looks like this:

using (ZipFile zip = new ZipFile())
{
    zip.AddEntry("Readme.txt", stringContent1);
    zip.AddEntry("readings/Data.csv", stringContent2);
    zip.AddEntry("readings/Index.xml", stringContent3);
    zip.Save("Archive1.zip"); 
}

The code above assumes stringContent{1,2,3} contains the data to be stored in the files (or entries) in the zip archive. The first entry is "Readme.txt" and it is stored in the top level "Directory" in the zip archive. The next two entries are stored in the "readings" directory in the zip archive.

The strings are encoded in the default encoding. There is an overload of AddEntry(), not shown here, that allows you to explicitly specify the encoding to use.

If you have the content in a stream or byte array, not a string, there are overloads for AddEntry() that accept those types. There are also overloads that accept a Write delegate, a method of yours that is invoked to write data into the zip. This works for easily saving a DataSet into a zip file, for example.

DotNetZip is free and open source.

Cheeso