Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a ZIP archive in memory using System.IO.Compression

People also ask

How do you compress a zip file?

ZIPPING/COMPRESSING FILES ON A PC Press and hold or right-click on the file or folder (to select multiple files, hold down the [Ctrl] key on your keyboard and click on each file you wish to zip) Select "send to" Select "Compressed (zipped) folder"

Are zip files good for archiving?

If you do zip your files, you may want to consider one file per archive. This will not give as good compression as multiple file archives, but will give reasonable data security.


Thanks to ZipArchive creates invalid ZIP file, I got:

using (var memoryStream = new MemoryStream())
{
   using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
   {
      var demoFile = archive.CreateEntry("foo.txt");

      using (var entryStream = demoFile.Open())
      using (var streamWriter = new StreamWriter(entryStream))
      {
         streamWriter.Write("Bar!");
      }
   }

   using (var fileStream = new FileStream(@"C:\Temp\test.zip", FileMode.Create))
   {
      memoryStream.Seek(0, SeekOrigin.Begin);
      memoryStream.CopyTo(fileStream);
   }
}

That indicated we need to call Dispose on ZipArchive before we can use it, which as Amir suggests is likely because it writes final bytes like checksum to the archive that makes it complete. But in order not close the stream so we can re-use it after you need to pass true as the third parameter to ZipArchive.


Just another version of zipping without writing any file.

string fileName = "export_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".xlsx";
byte[] fileBytes = here is your file in bytes
byte[] compressedBytes;
string fileNameZip = "Export_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".zip";

using (var outStream = new MemoryStream())
{
    using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
    {
        var fileInArchive = archive.CreateEntry(fileName, CompressionLevel.Optimal);
        using (var entryStream = fileInArchive.Open())
        using (var fileToCompressStream = new MemoryStream(fileBytes))
        {
            fileToCompressStream.CopyTo(entryStream);
        }
    }
    compressedBytes = outStream.ToArray();
}

Set the position of the stream to the 0 before copying it to the zip stream.

using (var memoryStream = new MemoryStream())
{
 using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
 {
  var demoFile = archive.CreateEntry("foo.txt");

  using (var entryStream = demoFile.Open())
  using (var streamWriter = new StreamWriter(entryStream))
  {
     streamWriter.Write("Bar!");
  }
 }

 using (var fileStream = new FileStream(@"C:\Temp\test.zip", FileMode.Create))
   {
     memoryStream.Position=0;
     memoryStream.WriteTo(fileStream);
   }
 }

Working solution for MVC

    public ActionResult Index()
    {
        string fileName = "test.pdf";
        string fileName1 = "test.vsix";
        string fileNameZip = "Export_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".zip";

        byte[] fileBytes = System.IO.File.ReadAllBytes(@"C:\test\test.pdf");
        byte[] fileBytes1 = System.IO.File.ReadAllBytes(@"C:\test\test.vsix");
        byte[] compressedBytes;
        using (var outStream = new MemoryStream())
        {
            using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
            {
                var fileInArchive = archive.CreateEntry(fileName, CompressionLevel.Optimal);
                using (var entryStream = fileInArchive.Open())
                using (var fileToCompressStream = new MemoryStream(fileBytes))
                {
                    fileToCompressStream.CopyTo(entryStream);
                }

                var fileInArchive1 = archive.CreateEntry(fileName1, CompressionLevel.Optimal);
                using (var entryStream = fileInArchive1.Open())
                using (var fileToCompressStream = new MemoryStream(fileBytes1))
                {
                    fileToCompressStream.CopyTo(entryStream);
                }


            }
            compressedBytes = outStream.ToArray();
        }
        return File(compressedBytes, "application/zip", fileNameZip);
    }

You need to finish writing the memory stream then read the buffer back.

        using (var memoryStream = new MemoryStream())
        {
            using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create))
            {
                var demoFile = archive.CreateEntry("foo.txt");

                using (var entryStream = demoFile.Open())
                using (var streamWriter = new StreamWriter(entryStream))
                {
                    streamWriter.Write("Bar!");
                }
            }

            using (var fileStream = new FileStream(@"C:\Temp\test.zip", FileMode.Create))
            {
                var bytes = memoryStream.GetBuffer();
                fileStream.Write(bytes,0,bytes.Length );
            }
        }

using System;
using System.IO;
using System.IO.Compression;

namespace ConsoleApplication
{
    class Program`enter code here`
    {
        static void Main(string[] args)
        {
            using (FileStream zipToOpen = new FileStream(@"c:\users\exampleuser\release.zip", FileMode.Open))
            {
                using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
                {
                    ZipArchiveEntry readmeEntry = archive.CreateEntry("Readme.txt");
                    using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
                    {
                            writer.WriteLine("Information about this package.");
                            writer.WriteLine("========================");
                    }
                }
            }
        }
    }
}

I'm late to the party, but there are scenarios where you can't access the ZipArchive's constructor to set the leaveOpen parameter and where you don't want the ZIP to be written to disk. In my case, the AsiceArchive class I'm using internally creates a ZipArchive but doesn't set leaveOpen to true.

I created a subclass of Stream that delegates all calls to an inner stream (a few clicks with ReSharper). This class is not disposable, so when the ZipArchive gets disposed, nothing happens to the inner stream.

public class NondisposingStreamWrapper : Stream
{
    private readonly Stream _streamImplementation;

    public NondisposingStreamWrapper(Stream inner) => _streamImplementation = inner;

    public override void Flush() => _streamImplementation.Flush();

    public override int Read(byte[] buffer, int offset, int count) => _streamImplementation.Read(buffer, offset, count);

    public override long Seek(long offset, SeekOrigin origin) => _streamImplementation.Seek(offset, origin);

    public override void SetLength(long value) => _streamImplementation.SetLength(value);

    public override void Write(byte[] buffer, int offset, int count) => _streamImplementation.Write(buffer, offset, count);

    public override bool CanRead => _streamImplementation.CanRead;

    public override bool CanSeek => _streamImplementation.CanSeek;

    public override bool CanWrite => _streamImplementation.CanWrite;

    public override long Length => _streamImplementation.Length;

    public override long Position
    {
        get => _streamImplementation.Position;
        set => _streamImplementation.Position = value;
    }
}

Use it like this:

using var memoryStream = new MemoryStream();
var output = new NondisposingStreamWrapper(memoryStream);

using (var archive = new ZipArchive(output, ZipArchiveMode.Create))
{
    // add entries to archive
}

memoryStream.Flush();
memoryStream.Position = 0;

// write to file just for testing purposes
File.WriteAllBytes("out.zip", memoryStream.ToArray());