Unzip a memorystream (Contains the zip file) and get the files

后端 未结 4 482
予麋鹿
予麋鹿 2020-11-27 16:31

I have a memory stream that contains a zip file in byte[] format .

Is there any way I can unzip this memory stream, without any need of writing the file to disk ?

相关标签:
4条回答
  • 2020-11-27 16:56

    I've just had a similar issue and the answer I found which I think seems to be fairly elegant is to use #ZipLib (available using nuget) and do the following:

    private byte[] GetUncompressedPayload(byte[] data)
    {
        using (var outputStream = new MemoryStream())
        using (var inputStream = new MemoryStream(data))
        {
            using (var zipInputStream = new ZipInputStream(inputStream))
            {
                zipInputStream.GetNextEntry();
                zipInputStream.CopyTo(outputStream);
            }
            return outputStream.ToArray();
        }
    }
    

    This seems to have worked a treat. Hope this helps.

    0 讨论(0)
  • 2020-11-27 16:58

    We use DotNetZip, and I can unzip the contents of a zip file from a Stream into memory. Here's the sample code for extracting a specifically named file from a stream (LocalCatalogZip) and returning a stream to read that file, but it'd be easy to expand on it.

    private static MemoryStream UnZipCatalog()
    {
        MemoryStream data = new MemoryStream();
        using (ZipFile zip = ZipFile.Read(LocalCatalogZip))
        {
            zip["ListingExport.txt"].Extract(data);
        }
        data.Seek(0, SeekOrigin.Begin);
        return data;
    }
    

    It's not the library you're using now, but if you can change, you can get that functionality.


    Here's a variation which would return a Dictionary<string,MemoryStream> of for the contents of every file of a zip file.

    private static Dictionary<string,MemoryStream> UnZipToMemory()
    {
        var result = new Dictionary<string,MemoryStream>();
        using (ZipFile zip = ZipFile.Read(LocalCatalogZip))
        {
            foreach (ZipEntry e in zip)
            {
                MemoryStream data = new MemoryStream();
                e.Extract(data);
                result.Add(e.FileName, data);
            }
        }
    
        return result;
    }
    
    0 讨论(0)
  • 2020-11-27 17:06

    Yes, Change from using FastZip To new ZipFile(stream), but this only works if your stream can seek. (Just use your MemoryStream in new ZipFile(fs); instead of reading a file stream like the example.)

    C#
    using ICSharpCode.SharpZipLib.Core;
    using ICSharpCode.SharpZipLib.Zip;
    
    public void ExtractZipFile(string archiveFilenameIn, string password, string outFolder) {
        ZipFile zf = null;
        try {
            FileStream fs = File.OpenRead(archiveFilenameIn);
            zf = new ZipFile(fs);
            if (!String.IsNullOrEmpty(password)) {
                zf.Password = password;     // AES encrypted entries are handled automatically
            }
            foreach (ZipEntry zipEntry in zf) {
                if (!zipEntry.IsFile) {
                    continue;           // Ignore directories
                }
                String entryFileName = zipEntry.Name;
                // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
                // Optionally match entrynames against a selection list here to skip as desired.
                // The unpacked length is available in the zipEntry.Size property.
    
                byte[] buffer = new byte[4096];     // 4K is optimum
                Stream zipStream = zf.GetInputStream(zipEntry);
    
                // Manipulate the output filename here as desired.
                String fullZipToPath = Path.Combine(outFolder, entryFileName);
                string directoryName = Path.GetDirectoryName(fullZipToPath);
                if (directoryName.Length > 0)
                    Directory.CreateDirectory(directoryName);
    
                // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                // of the file, but does not waste memory.
                // The "using" will close the stream even if an exception occurs.
                using (FileStream streamWriter = File.Create(fullZipToPath)) {
                    StreamUtils.Copy(zipStream, streamWriter, buffer);
                }
            }
        } finally {
            if (zf != null) {
                zf.IsStreamOwner = true; // Makes close also shut the underlying stream
                zf.Close(); // Ensure we release resources
            }
        }
    }
    

    If you are using a non-seekable stream use ZipInputStream.

    // Calling example:
        WebClient webClient = new WebClient();
        Stream data = webClient.OpenRead("http://www.example.com/test.zip");
        // This stream cannot be opened with the ZipFile class because CanSeek is false.
        UnzipFromStream(data, @"c:\temp");
    
    public void UnzipFromStream(Stream zipStream, string outFolder) {
    
        ZipInputStream zipInputStream = new ZipInputStream(zipStream);
        ZipEntry zipEntry = zipInputStream.GetNextEntry();
        while (zipEntry != null) {
            String entryFileName = zipEntry.Name;
            // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
            // Optionally match entrynames against a selection list here to skip as desired.
            // The unpacked length is available in the zipEntry.Size property.
    
            byte[] buffer = new byte[4096];     // 4K is optimum
    
            // Manipulate the output filename here as desired.
            String fullZipToPath = Path.Combine(outFolder, entryFileName);
            string directoryName = Path.GetDirectoryName(fullZipToPath);
            if (directoryName.Length > 0)
                Directory.CreateDirectory(directoryName);
    
            // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
            // of the file, but does not waste memory.
            // The "using" will close the stream even if an exception occurs.
            using (FileStream streamWriter = File.Create(fullZipToPath)) {
                StreamUtils.Copy(zipInputStream, streamWriter, buffer);
            }
            zipEntry = zipInputStream.GetNextEntry();
        }
    }
    

    Examples taken from the ICSharpCode Wiki

    0 讨论(0)
  • 2020-11-27 17:19

    Yes, .Net 4.5 now supports more Zip functionality.

    Here is a code example based on your description.

    In your project, right click on the References folder and add a reference to System.IO.Compression

    using System.IO.Compression;
    
    Stream data = new MemoryStream(); // The original data
    Stream unzippedEntryStream; // Unzipped data from a file in the archive
    
    ZipArchive archive = new ZipArchive(data);
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
        if(entry.FullName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
        {
             unzippedEntryStream = entry.Open(); // .Open will return a stream
             // Process entry data here
        }
    }
    

    Hope this helps.

    0 讨论(0)
提交回复
热议问题