53

I am trying to create a new ZIP package from code with one entry and save the ZIP package to a file. I am trying to achive this with the System.IO.Compression.ZipArchive class. I am creating the ZIP package with the following code:

using (MemoryStream zipStream = new MemoryStream())
{
    using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create))
    {
        var entry = zip.CreateEntry("test.txt");
        using (StreamWriter sw = new StreamWriter(entry.Open()))
        {
            sw.WriteLine(
                "Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
        }

Then I save the ZIP to a file either in WinRT:

        var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("test.zip", CreationCollisionOption.ReplaceExisting);
        zipStream.Position = 0;
        using (Stream s = await file.OpenStreamForWriteAsync())
        {
            zipStream.CopyTo(s);
        }

Or in normal .NET 4.5:

        using (FileStream fs = new FileStream(@"C:\Temp\test.zip", FileMode.Create))
        {
            zipStream.Position = 0;
            zipStream.CopyTo(fs);
        }

However, I can't open the produced files neither in Windows Explorer, WinRAR, etc. (I checked that the size of the produced file matches the Length of the zipStream, so the stream itself was saved to the file correctly.)
Am I doing something wrong or is there a problem with the ZipArchive class?

4

6 回答 6

107

I found the—in hindsight, obvious—error in my code. The ZipArchive has to be disposed to make it write its content to its underlying stream. So I had to save the stream to a file after the end of the using block of the ZipArchive.
And it was important to set the leaveOpen argument of its constructor to true, to make it not close the underlying stream. So here is the complete working solution:

using (MemoryStream zipStream = new MemoryStream())
{
    using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
    {
        var entry = zip.CreateEntry("test.txt");
        using (StreamWriter sw = new StreamWriter(entry.Open()))
        {
            sw.WriteLine(
                "Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
        }
    }

    var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(
        "test.zip",
        CreationCollisionOption.ReplaceExisting);

    zipStream.Position = 0;
    using (Stream s = await file.OpenStreamForWriteAsync())
    {
        zipStream.CopyTo(s);
    }
}
于 2012-09-10T10:48:30.647 回答
4

On all of your Stream Object you must rewind the streams from the beggining in order from them to be read correctly by other applications using the .Seek method.

Example:

zipStream.Seek(0, SeekOrigin.Begin);
于 2012-09-10T08:24:55.537 回答
2
// Create file "archive.zip" in current directory use it as destination for ZIP archive
using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"), 
ZipArchiveMode.Create))
{
    // Create entry inside ZIP archive with name "test.txt"
    using (var entry = zipArchive.CreateEntry("test.txt").Open())
    {
        // Copy content from current directory file "test.txt" into created ZIP entry 
        using (var file = File.OpenRead("test.txt"))
        {
            file.CopyTo(entry);
        }
    }
}    

In result you will get archive "archive.zip" with single entry file "test.txt". You need this cascade of using to avoid any interaction with already disposed resources.

于 2017-05-31T09:04:33.633 回答
1

You can follow the same idea, only in reverse order, using the file stream like source. I did the form below and the file was opened normally:

string fileFormat = ".zip"; // any format
string filename = "teste" + fileformat;

StorageFile zipFile = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(filename,CreationCollisionOption.ReplaceExisting);

using (Stream zipStream = await zipFile.OpenStreamForWriteAsync()){

   using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)){
        //Include your content here
   }
}
于 2013-02-28T21:43:52.947 回答
0

The complete code looks like this:

var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("test.zip",CreationCollisionOption.ReplaceExisting);
using (Stream zipStream = await zipFile.OpenStreamForWriteAsync())
{
    using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
    {
        var entry = zip.CreateEntry("test.txt");
        using (StreamWriter sw = new StreamWriter(entry.Open()))
        {
            sw.WriteLine("Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
        }
    }   
}
于 2013-02-28T21:48:53.727 回答
0

In My case the Issue was that I was not disposing "zipArchive" when the zip file Task Completes. Even though I was flushing and closing all the streams.

So, Either use using as suggested in answers above

using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"), 
ZipArchiveMode.Create))

Or Dispose the variable at the end of the Task...

zipArchive.Dispose();
于 2019-07-10T05:17:47.227 回答