ZipArchive creates invalid ZIP file

C#.NetWindows 8Ziparchive

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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);
    }
}

Solution 2 - C#

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);

Solution 3 - C#

// 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.

Solution 4 - C#

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
   }
}

Solution 5 - C#

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();

Solution 6 - C#

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.");
		}
	}   
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMark VinczeView Question on Stackoverflow
Solution 1 - C#Mark VinczeView Answer on Stackoverflow
Solution 2 - C#FreemanView Answer on Stackoverflow
Solution 3 - C#Andrew DraganView Answer on Stackoverflow
Solution 4 - C#Robert MeloView Answer on Stackoverflow
Solution 5 - C#Ritesh MishraView Answer on Stackoverflow
Solution 6 - C#Robert MeloView Answer on Stackoverflow