ZipArchive 创建无效的 ZIP 文件
Posted
技术标签:
【中文标题】ZipArchive 创建无效的 ZIP 文件【英文标题】:ZipArchive creates invalid ZIP file 【发布时间】:2012-09-10 08:21:44 【问题描述】:我正在尝试使用一个条目从代码创建一个新的 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.");
然后我将 ZIP 保存到 WinRT 中的文件:
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);
或者在普通的 .NET 4.5 中:
using (FileStream fs = new FileStream(@"C:\Temp\test.zip", FileMode.Create))
zipStream.Position = 0;
zipStream.CopyTo(fs);
但是,我无法在 Windows 资源管理器、WinRAR 等中打开生成的文件(我检查了生成文件的大小是否与 zipStream 的长度匹配,因此流本身已正确保存到文件中。 ) 我做错了什么还是 ZipArchive 类有问题?
【问题讨论】:
如果您要添加二进制数据而不是字符串,这是一个很好的示例:***.com/questions/48927574/… 【参考方案1】:我在我的代码中发现了——事后看来,很明显——错误。 ZipArchive 必须被disposed 以使其将其内容写入其底层流。所以我不得不在 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);
【讨论】:
我收到错误消息“当前上下文中不存在名称‘Windows’”。我该如何纠正这个问题? Michael,这是构建错误,对吧?您是在开发 Windows 应用商店应用程序,还是普通的 .NET 应用程序?在普通的 .NET 应用程序中,您应该使用FileStream
类,而不是 Windows.Storage
命名空间中的存储类。您可以在问题中看到一个示例。【参考方案2】:
在您的所有 Stream 对象上,您必须从开头倒回流,以便其他应用程序使用 .Seek 方法正确读取它们。
例子:
zipStream.Seek(0, SeekOrigin.Begin);
【讨论】:
这没有帮助。这就是为什么我将 Position 属性设置为 0,我猜这样可以达到相同的效果。 zip 库必须有自己的 SaveAs 方法,尝试研究一下,在项目 peage 上也有各种不同保存场景的文档。 嗯,ZipArchive 类 (msdn.microsoft.com/en-us/library/…) 没有 SaveAs 方法。 “项目页面”是什么意思? 对不起,我以为是第 3 方库。 @Freeman 这在我的案例中起到了作用。谢谢!【参考方案3】:// 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);
结果,您将获得包含单个条目文件“test.txt”的存档“archive.zip”。
您需要这种级联的using
来避免与已释放资源的任何交互。
【讨论】:
请为您的代码添加解释,以及它如何解决问题。 @DouglasGaskell 完成。可能上面的代码没有直接回答问题,而是展示了如何使用 ZipArchive 压缩一些文件【参考方案4】:您可以遵循相同的想法,只是以相反的顺序,使用类似源的文件流。我做了下面的表格,文件正常打开了:
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
【讨论】:
【参考方案5】:完整的代码如下所示:
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.");
【讨论】:
【参考方案6】:在我的情况下,问题是当 zip 文件任务完成时我没有处理 "zipArchive"。即使我正在刷新并关闭所有流。
因此,请按照上述答案中的建议使用 using
using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"),
ZipArchiveMode.Create))
或者在任务结束时释放变量...
zipArchive.Dispose();
【讨论】:
以上是关于ZipArchive 创建无效的 ZIP 文件的主要内容,如果未能解决你的问题,请参考以下文章
我使用 PHP 的 ZipArchive 创建的 .zip 存档在 Windows 10 上已损坏/无效
PHP:使用 ZipArchive 创建 zip 文件时出现错误 (500)
Laravel 8,为公共文件夹中的所有图像创建 zip 文件。面对文件错误:ZipArchive::addFile(): Invalid or uninitialized Zip object