How can I unzip a file to a .NET memory stream?

C#.NetFtp

C# Problem Overview


I have files (from 3rd parties) that are being FTP'd to a directory on our server. I download them and process them even 'x' minutes. Works great.

Now, some of the files are .zip files. Which means I can't process them. I need to unzip them first.

FTP has no concept of zip/unzipping - so I'll need to grab the zip file, unzip it, then process it.

Looking at the MSDN zip api, there seems to be no way i can unzip to a memory stream?

So is the only way to do this...

  1. Unzip to a file (what directory? need some -very- temp location ...)
  2. Read the file contents
  3. Delete file.

NOTE: The contents of the file are small - say 4k <-> 1000k.

C# Solutions


Solution 1 - C#

Zip compression support is built in:

using System.IO;
using System.IO.Compression;
// ^^^ requires a reference to System.IO.Compression.dll
static class Program
{
    const string path = ...
    static void Main()
    {
        using(var file = File.OpenRead(path))
        using(var zip = new ZipArchive(file, ZipArchiveMode.Read))
        {
            foreach(var entry in zip.Entries)
            {
                using(var stream = entry.Open())
                {
                    // do whatever we want with stream
                    // ...
                }
            }
        }
    }
}

Normally you should avoid copying it into another stream - just use it "as is", however, if you absolutely need it in a MemoryStream, you could do:

using(var ms = new MemoryStream())
{
    stream.CopyTo(ms);
    ms.Position = 0; // rewind
    // do something with ms
}

Solution 2 - C#

You can use ZipArchiveEntry.Open to get a stream.

This code assumes the zip archive has one text file.

using (FileStream fs = new FileStream(path, FileMode.Open))
using (ZipArchive zip = new ZipArchive(fs) )
{
    var entry = zip.Entries.First();

    using (StreamReader sr = new StreamReader(entry.Open()))
    {
        Console.WriteLine(sr.ReadToEnd());
    }
}

Solution 3 - C#

using (ZipArchive archive = new ZipArchive(webResponse.GetResponseStream()))
{
     foreach (ZipArchiveEntry entry in archive.Entries)
     {
        Stream s = entry.Open();
        var sr = new StreamReader(s);
        var myStr = sr.ReadToEnd();
     }
} 

Solution 4 - C#

Looks like here is what you need:

using (var za = ZipFile.OpenRead(path))
{
    foreach (var entry in za.Entries)
    {
        using (var r = new StreamReader(entry.Open()))
        {
            //your code here
        }
    }
}

Solution 5 - C#

Ok so combining all of the above, suppose you want to in a very simple way take a zip file called "file.zip" and extract it to "C:\temp" folder. (Note: This example was only tested for compress text files) You may need to do some modifications for binary files.

        using System.IO;
        using System.IO.Compression;
        
        static void Main(string[] args)
        {
            //Call it like this:
            Unzip("file.zip",@"C:\temp");
        }

        static void Unzip(string sourceZip, string targetPath)
        {
            using (var z = ZipFile.OpenRead(sourceZip))
            {
                foreach (var entry in z.Entries)
                {                    
                    using (var r = new StreamReader(entry.Open()))
                    {
                        string uncompressedFile = Path.Combine(targetPath, entry.Name);
                        File.WriteAllText(uncompressedFile,r.ReadToEnd());
                    }
                }
            }

        }

Solution 6 - C#

You can use SharpZipLib among a variety of other libraries to achieve this.

You can use the following code example to unzip to a MemoryStream, as shown on their wiki:

using ICSharpCode.SharpZipLib.Zip;

// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,
// which is returned as a memory stream or a byte array.
//
public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {

    MemoryStream outputMemStream = new MemoryStream();
    ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);

    zipStream.SetLevel(3); //0-9, 9 being the highest level of compression

    ZipEntry newEntry = new ZipEntry(zipEntryName);
    newEntry.DateTime = DateTime.Now;

    zipStream.PutNextEntry(newEntry);

    StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
    zipStream.CloseEntry();

    zipStream.IsStreamOwner = false;    // False stops the Close also Closing the underlying stream.
    zipStream.Close();          // Must finish the ZipOutputStream before using outputMemStream.

    outputMemStream.Position = 0;
    return outputMemStream;

    // Alternative outputs:
    // ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
    byte[] byteArrayOut = outputMemStream.ToArray();

    // GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.
    byte[] byteArrayOut = outputMemStream.GetBuffer();
    long len = outputMemStream.Length;
}

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
QuestionPure.KromeView Question on Stackoverflow
Solution 1 - C#Marc GravellView Answer on Stackoverflow
Solution 2 - C#dcastroView Answer on Stackoverflow
Solution 3 - C#Zia KhanView Answer on Stackoverflow
Solution 4 - C#UriilView Answer on Stackoverflow
Solution 5 - C#Alex BegunView Answer on Stackoverflow
Solution 6 - C#aevitasView Answer on Stackoverflow