C# 解压缩内存流(包含 zip 文件)并获取文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12715945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unzip a memorystream (Contains the zip file) and get the files
提问by Deepak Jena
I have a memory stream that contains a zip file in byte[] format .
我有一个包含 byte[] 格式的 zip 文件的内存流。
Is there any way I can unzip this memory stream, without any need of writing the file to disk ?
有什么办法可以解压缩这个内存流,而无需将文件写入磁盘?
In general I am using ICSharpCode.SharpZipLib.Zip.FastZip to unzip a file , But any way to unzip a memory stream ? and store the files in another memorystream or in byte[] format according to the files/folders present in the zip ?
一般来说,我使用 ICSharpCode.SharpZipLib.Zip.FastZip 解压缩文件,但有什么方法可以解压缩内存流?并根据 zip 中存在的文件/文件夹将文件存储在另一个内存流或字节 [] 格式中?
Any way I can use the Memorymapped files feature in this scenario ?
在这种情况下,我可以通过什么方式使用 Memorymapped 文件功能?
采纳答案by Bobson
We use DotNetZip, and I can unzip the contents of a zip file from a Streaminto 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.
我们使用DotNetZip,我可以将 zip 文件的内容从 a 解压缩Stream到内存中。下面是用于从流 ( LocalCatalogZip) 中提取特定命名文件并返回流以读取该文件的示例代码,但很容易对其进行扩展。
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.
这是一个变体,它将Dictionary<string,MemoryStream>为 zip 文件的每个文件的内容返回 a 。
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;
}
回答by Scott Chamberlain
Yes, Change from using FastZipTo 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.)
是的,不要使用FastZipTo new ZipFile(stream),但这只有在您的流可以搜索时才有效。(只需使用您的 MemoryStreamnew ZipFile(fs);而不是像示例那样读取文件流。)
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.
如果您使用的是不可搜索的流,请使用 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
回答by kipper_t
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:
我刚刚遇到了一个类似的问题,我发现我认为似乎相当优雅的答案是使用#ZipLib(使用nuget可用)并执行以下操作:
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.
这似乎是一种享受。希望这可以帮助。
回答by gigaduck
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
在您的项目中,右键单击 References 文件夹并添加对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.
希望这可以帮助。

