ZipArchive 创建无效的 ZIP 文件

问题描述 投票:0回答:7

我正在尝试从具有一个条目的代码创建一个新的 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 类有问题吗?

c# .net windows-8 ziparchive
7个回答
129
投票

事后看来,我在代码中发现了明显的错误。 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); } }



5
投票
结果您将获得包含单个条目文件“test.txt”的存档“archive.zip”。
您需要这种级联 
using

以避免与已处置的资源发生任何交互。

    


4
投票

示例:

zipStream.Seek(0, SeekOrigin.Begin);



2
投票
“zipArchive”

。即使我正在冲洗并关闭所有流。 所以,要么按照上面答案中的建议使用

using using (var zipArchive = new ZipArchive(File.OpenWrite("archive.zip"), ZipArchiveMode.Create))

或者在任务结束时释放变量...

zipArchive.Dispose();



1
投票

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



0
投票

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."); } } }



0
投票

static byte[] CompressAsZip(string fileName, Stream fileStram) { using var memoryStream = new MemoryStream(); using var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, false); using var entryStream = archive.CreateEntry(fileName).Open(); fileStram.CopyTo(entryStream); archive.Dispose(); //<- Necessary to close the archive correctly return memoryStream.ToArray(); }

使用带大括号的 using 语句,archive.Dispose 将在作用域末尾隐式调用。
另外,由于您使用的是 C# >8.0,我建议使用这种类型的异步实现,能够归档多个文件并被取消:

static async Task<byte[]> CompressAsZipAsync( IAsyncEnumerable<(string FileName, Stream FileStream)> files, bool disposeStreamsAfterCompression = false, CancellationToken cancellationToken = default) { using var memoryStream = new MemoryStream(); using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, false)) { await foreach (var (FileName, FileStream) in files.WithCancellation(cancellationToken)) { using var entryStream = archive.CreateEntry(FileName).Open(); await FileStream.CopyToAsync(entryStream, cancellationToken); if (disposeStreamsAfterCompression) await FileStream.DisposeAsync(); } } return memoryStream.ToArray(); }

© www.soinside.com 2019 - 2024. All rights reserved.