Unzip a Memorystream (Containing the Zip File) and Get the Files

Unzip a MemoryStream (containing the zip file) and get the files

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

Save a zip file to memory and unzip file from stream and get content

I was overthinking it. I finally found a simple way to do it. We just need to convert that base64 string to bytes array and use GzipStream to directly decompress it. I leave the solution here in case someone needs it. Thanks!

var label = Convert.FromBase64String(str);

using (var compressedStream = new MemoryStream(label))
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
return resultStream.ToArray();
}

Unzipping a Stream in C#

I am using SharpZipLib and it's working great !

Below is a function that encapsulate the library

 public static void Compress(FileInfo sourceFile, string destinationFileName,string destinationTempFileName)
{
Crc32 crc = new Crc32();
string zipFile = Path.Combine(sourceFile.Directory.FullName, destinationTempFileName);
zipFile = Path.ChangeExtension(zipFile, ZIP_EXTENSION);

using (FileStream fs = File.Create(zipFile))
{
using (ZipOutputStream zOut = new ZipOutputStream(fs))
{
zOut.SetLevel(9);
ZipEntry entry = new ZipEntry(ZipEntry.CleanName(destinationFileName));

entry.DateTime = DateTime.Now;
entry.ZipFileIndex = 1;
entry.Size = sourceFile.Length;

using (FileStream sourceStream = sourceFile.OpenRead())
{
crc.Reset();
long len = sourceFile.Length;
byte[] buffer = new byte[bufferSize];
while (len > 0)
{
int readSoFar = sourceStream.Read(buffer, 0, buffer.Length);
crc.Update(buffer, 0, readSoFar);
len -= readSoFar;
}
entry.Crc = crc.Value;
zOut.PutNextEntry(entry);

len = sourceStream.Length;
sourceStream.Seek(0, SeekOrigin.Begin);
while (len > 0)
{
int readSoFar = sourceStream.Read(buffer, 0, buffer.Length);
zOut.Write(buffer, 0, readSoFar);
len -= readSoFar;
}
}
zOut.Finish();
zOut.Close();
}
fs.Close();
}
}

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

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
}

Extract files from stream containing zip

ZipArchiveEntry has a Name and FullName property that can be used to get the names of the files within the archive while preserving their original filenames and extensions

The FullName property contains the relative path, including the subdirectory hierarchy, of an entry in a zip archive. (In contrast, the Name property contains only the name of the entry and does not include the subdirectory hierarchy.)

For example

using (ZipArchive archive = new ZipArchive(await response.Content.ReadAsStreamAsync())) {
foreach (ZipArchiveEntry entry in archive.Entries) {
using (Stream stream = entry.Open()) {
string destination = Path.GetFullPath(Path.Combine(downloadPath, entry.FullName));

var directory = Path.GetDirectoryName(destination);
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);

using (FileStream file = new FileStream(destination, FileMode.Create, FileAccess.Write)) {
await stream.CopyToAsync(file);
}
}
}
}

will extract the files in the same subdirectory hierarchy as they were stored in the archive while if entry.Name was used, all the files would be extracted to the same location.

Decompressing a zipfile into memory stream - C#

You'll want to convert your file content to a memory stream (Stream filestream = new MemoryStream(filecontent)) then use ZipFile.Read(fileStream). Then use a StreamReader to get the contents out as a string. So try something like this (note it's untested):

string myString;
byte[] filecontent = Convert.FromBase64String(strcontent);
using (var filestream = new MemoryStream(filecontent))
{
using (ZipFile zip = ZipFile.Read(filestream))
{
foreach (ZipEntry entry in zip.Entries)
{
if ((entry.FileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) ||
(entry.FileName.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase)))
{
using (var ms = new MemoryStream())
{
entry.ExtractWithPassword(ms, "password");

ms.Position = 0;
var sr = new StreamReader(ms);
myString = sr.ReadToEnd();
}
...

If the results should be a base64 string, do this:

                    entry.ExtractWithPassword(ms, "password");

ms.Position = 0;
myString = Convert.ToBase64String(ms.ToArray());

You may or may not have to reset the stream position, but it's good practice to.

Now you can use the results as a string without having to write to a file first.

Open ZIP Package from MemoryStream

How you can handle .zip files, depends on the Framework version you are using. Streams are fully interchangeable and can even encapsulate one another. The question is if you have a class that can actually take a stream and do zip Operations.

If you have at least Framework 4.5, you got the ZipArchive class and this whole thing is childsplay. The examples take a Stream and it can be any implemention of the Stream abstract class. All that memory stream is, is a readyonly stream.

If you are under that, I am pretty sure you are hosed. There simply is no class that can take a Stream and do ZIP operations on it before 4.5. Most approaches invovle saving the .zip file on the disk and decompressing it using a console programm with IO redirection. Both Windows ZIP functionaltiy and 7zip work for that, but both involve writing on the Disk.

Perhaps you can use the code part of 7-zip to do a in-process/in memory zip operation. But that might be a tricky.

.net core unzip a file and zip subfolder

please try below code

   using (MemoryStream srcMemoryStream = new MemoryStream())
{
using (MemoryStream targetMemoryStream = new MemoryStream())
{
// to have a byte array, I just read a file and store it into a memory stream
using (FileStream sourceZipFile = new FileStream(@"f:\source-file.zip", FileMode.Open))
{
sourceZipFile.CopyTo(srcMemoryStream);
}

using (ZipArchive srcArchive = new ZipArchive(srcMemoryStream, ZipArchiveMode.Read))
{
using (ZipArchive destArchive = new ZipArchive(targetMemoryStream, ZipArchiveMode.Create, true))
{

srcArchive.Entries
.Where(entry => entry.FullName.Contains("dist/"))
.ToList()
.ForEach((entry) =>
{
// i simply create the same folder with the same structure in other archive
// if you want to change the structure, you have to rename or remove parts of
// the path like below
/// var newEntryName = entry.FullName.Replace("files/dist/", "new-dist/");
/// ZipArchiveEntry newEntry = destArchive.CreateEntry(newEntryName);
ZipArchiveEntry newEntry = destArchive.CreateEntry(entry.FullName);
using (Stream srcEntry = entry.Open())
{
using (Stream destEntry = newEntry.Open())
{
srcEntry.CopyTo(destEntry);
}
}
});
}
}

// i just write the zip file on disk to make sure that it works, your desire state is already achieved
// before this line of code, and the result byte Array is inside the targetMemoryStream memory stream
using (FileStream fs = new FileStream(@"f:/destination-file.zip", FileMode.Create))
{
targetMemoryStream.WriteTo(fs);
targetMemoryStream.Flush();
fs.Flush(true);
}

}
}

you can store those byte arrays in the memory stream, I just read a file and store it into a memory stream but you can simply use below code:

MemoryStream srcMemoryStream = new MemoryStream();
srcMemoryStream.Write(byteArray, 0, byteArray.Length);


Related Topics



Leave a reply



Submit