【问题标题】:ZipArchive does not flush zip item immediatelyZipArchive 不会立即刷新 zip 项目
【发布时间】:2023-03-30 04:05:02
【问题描述】:

我正在使用 ZipArchive + FileStream 创建一个 zip 文件。当新项目添加到 zip 文件中时,我想将新添加的项目刷新/写入到 zip 流下面。

下面的代码不会刷新单个 zip 项目。当 FileStream 处理时,整个 zip 将被写入 output.zip。

        var files = Directory.GetFiles("C:\\Temp","*.pdf");
        using (var output = new FileStream("c:\\temp\\output.zip", FileMode.Create, FileAccess.Write))
        {
            using (System.IO.Compression.ZipArchive zip = new ZipArchive(output, ZipArchiveMode.Create, true))
            {                    
                foreach (var file in files)
                {
                    using (var internalFile = new FileStream(file, FileMode.Open))
                    {
                        
                        var zipItem = zip.CreateEntry(Path.GetFileName(file));
                                 
                        using var entryStream = zipItem.Open();
                        {
                            await internalFile.CopyToAsync(entryStream).ConfigureAwait(false);
                        }
                    }
                                            
                    await output.FlushAsync();

                    // after each file flush the output stream.
                    // expectation at this point, individual zip item will be written to physical file.
                    // however I don't see the file size changes in windows explorer.
                } // put breakpoint here
            }
        } // The whole output get flush at this point when FileStream is disposed            

【问题讨论】:

  • 我假设流将在缓冲区已满时刷新。文件是否大到足以导致这种情况?

标签: asp.net-core-3.1 coreclr system.io.compression


【解决方案1】:

我会说“这是设计使然”。

看起来确实很难获得任何不同的行为。

从设计的角度来看,这可能有价值的原因与 zip 过程的工作方式有关。它识别重复的字节序列,而不是多次写入该序列,而是写入一次,然后每当需要该字节序列时,它会写入引用,而不是整个序列。这就是 zip 文件变得比原始文件小的原因。 (警告:这是我的理解,通俗地说,我已经很久没有研究 zip 算法了)。

因此,在写入之前让整个文件可用是“有价值的”,以优化重复字节序列的识别。

这是一些类似于 ZipArchive 的代码,来自 dotnet 运行时 github 存储库。

https://github.com/dotnet/runtime/blob/6072e4d3a7a2a1493f514cdf4be75a3d56580e84/src/libraries/System.IO.Compression/src/System/IO/Compression/ZipArchive.cs

(它可能不是最新的,也可能不是您正在运行的实际版本)。

看起来压缩是通过private void WriteFile() 方法完成的。当然这就是seek(0) 发生的地方。此方法为private,仅引用自Dispose() 方法。

您的代码在您的输出流上调用FlushAsync()。这是一个标准的 IO 文件流。当您调用FlushAsync() 时,它将写入ZipArchive 对象给它的所有字节。不幸的是,这将是零字节。

您可以尝试在写入每个对象后处理 ZipArchive,但我认为这不是一个非常愉快的实验。我怀疑它每次都会重写整个流,而不是单独添加新元素(但我不确定)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-07
    • 2014-02-13
    • 2020-03-23
    • 2012-08-03
    • 1970-01-01
    • 2018-06-20
    • 2019-09-30
    • 2014-08-24
    相关资源
    最近更新 更多