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
How to Get a List of Keys from JSON.Net
Should I Unsubscribe from Events
How to Generate a Constructor from Class Fields Using Visual Studio (And/Or Resharper)
How to Get User Type C# Syntax Highlighting Working Again in VS 2012 Rc
I Want to Understand the Lambda Expression in @Html.Displayfor(Modelitem => Item.Firstname)
What Are the Benefits of Resource(.Resx) Files
Remove File Extension from a File Name String
Converting Xml to a Dynamic C# Object
Should You Obfuscate a Commercial .Net Application
How to Run Multiple SQL Commands in a Single SQL Connection
How to Extend Identityuser with Custom Property
Mock Httpcontext for Unit Testing a .Net Core MVC Controller
Should I Use Appdomain.Currentdomain.Basedirectory or System.Environment.Currentdirectory
Nested "From" Linq Query Expressed with Extension Methods