C# ZipArchive 创建无效的 ZIP 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12347775/
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
ZipArchive creates invalid ZIP file
提问by Mark Vincze
I am trying to create a new ZIP package from code with one entry and save the ZIP package to a file. I am trying to achive this with the System.IO.Compression.ZipArchiveclass. I am creating the ZIP package with the following code:
我正在尝试从一个条目的代码中创建一个新的 ZIP 包,并将该 ZIP 包保存到一个文件中。我正在尝试使用System.IO.Compression.ZipArchive类来实现这一点。我正在使用以下代码创建 ZIP 包:
using (MemoryStream zipStream = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create))
{
var entry = zip.CreateEntry("test.txt");
using (StreamWriter sw = new StreamWriter(entry.Open()))
{
sw.WriteLine(
"Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
}
Then I save the ZIP to a file either in WinRT:
然后我在 WinRT 中将 ZIP 保存到一个文件中:
var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("test.zip", CreationCollisionOption.ReplaceExisting);
zipStream.Position = 0;
using (Stream s = await file.OpenStreamForWriteAsync())
{
zipStream.CopyTo(s);
}
Or in normal .NET 4.5:
或者在普通的 .NET 4.5 中:
using (FileStream fs = new FileStream(@"C:\Temp\test.zip", FileMode.Create))
{
zipStream.Position = 0;
zipStream.CopyTo(fs);
}
However, I can't open the produced files neither in Windows Explorer, WinRAR, etc. (I checked that the size of the produced file matches the Length of the zipStream, so the stream itself was saved to the file correctly.)
Am I doing something wrong or is there a problem with the ZipArchive class?
但是,我无法在 Windows 资源管理器、WinRAR 等中打开生成的文件(我检查了生成的文件的大小是否与 zipStream 的长度匹配,因此流本身已正确保存到文件中。)
我是做错了什么还是 ZipArchive 类有问题?
采纳答案by Mark Vincze
I found the - in retrospective, obvious - error in my code. The ZipArchive has to be disposedto make it write its content to its underlying stream. So I had to save the stream to a file after the end of the using block of the ZipArchive.
And it was important to set the leaveOpenargument of its constructor to true, to make it not close the underlying stream. So here is the complete working solution:
我在我的代码中发现了 - 回顾性的,明显的 - 错误。必须处理ZipArchive以使其将其内容写入其底层流。所以我不得不在 ZipArchive 的 using 块结束后将流保存到一个文件中。
重要的是将其构造函数的leaveOpen参数设置为 true,使其不关闭底层流。所以这是完整的工作解决方案:
using (MemoryStream zipStream = new MemoryStream())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
var entry = zip.CreateEntry("test.txt");
using (StreamWriter sw = new StreamWriter(entry.Open()))
{
sw.WriteLine(
"Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
}
}
var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(
"test.zip",
CreationCollisionOption.ReplaceExisting);
zipStream.Position = 0;
using (Stream s = await file.OpenStreamForWriteAsync())
{
zipStream.CopyTo(s);
}
}
回答by Freeman
On all of your Stream Object you must rewind the streams from the beggining in order from them to be read correctly by other applications using the .Seek method.
在您的所有 Stream 对象上,您必须从头开始倒带流,以便其他应用程序使用 .Seek 方法正确读取它们。
Example:
例子:
zipStream.Seek(0, SeekOrigin.Begin);
回答by Robert Melo
You can follow the same idea, only in reverse order, using the file stream like source. I did the form below and the file was opened normally:
您可以遵循相同的想法,只是以相反的顺序使用文件流,如源。我做了下面的表格,文件正常打开:
string fileFormat = ".zip"; // any format
string filename = "teste" + fileformat;
StorageFile zipFile = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(filename,CreationCollisionOption.ReplaceExisting);
using (Stream zipStream = await zipFile.OpenStreamForWriteAsync()){
using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create)){
//Include your content here
}
}
回答by Robert Melo
The complete code looks like this:
完整的代码如下所示:
var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("test.zip",CreationCollisionOption.ReplaceExisting);
using (Stream zipStream = await zipFile.OpenStreamForWriteAsync())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
{
var entry = zip.CreateEntry("test.txt");
using (StreamWriter sw = new StreamWriter(entry.Open()))
{
sw.WriteLine("Etiam eros nunc, hendrerit nec malesuada vitae, pretium at ligula.");
}
}
}
回答by Andrew Dragan
// Create file "archive.zip" in current directory use it as destination for ZIP archive
using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"),
ZipArchiveMode.Create))
{
// Create entry inside ZIP archive with name "test.txt"
using (var entry = zipArchive.CreateEntry("test.txt").Open())
{
// Copy content from current directory file "test.txt" into created ZIP entry
using (var file = File.OpenRead("test.txt"))
{
file.CopyTo(entry);
}
}
}
In result you will get archive "archive.zip" with single entry file "test.txt".
You need this cascade of usingto avoid any interaction with already disposed resources.
结果,您将获得带有单个条目文件“test.txt”的存档“archive.zip”。您需要此级联using以避免与已处置的资源发生任何交互。
回答by Ritesh Mishra
In My case the Issue was that I was not disposing "zipArchive"when the zip file Task Completes. Even though I was flushing and closing all the streams.
在我的情况下,问题是当 zip 文件任务完成时我没有处理“zipArchive”。即使我正在冲洗并关闭所有流。
So, Either use usingas suggested in answers above
因此,请按照上述答案中的建议使用using
using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"),
ZipArchiveMode.Create))
Or Dispose the variable at the end of the Task...
或者在任务结束时处理变量...
zipArchive.Dispose();

