SharpCompress & LZMA2 7z 存档 - 特定文件的提取速度非常慢。为啥?备择方案?

Posted

技术标签:

【中文标题】SharpCompress & LZMA2 7z 存档 - 特定文件的提取速度非常慢。为啥?备择方案?【英文标题】:SharpCompress & LZMA2 7z archive - very slow extraction of specific file. Why? Alternatives?SharpCompress & LZMA2 7z 存档 - 特定文件的提取速度非常慢。为什么?备择方案? 【发布时间】:2017-04-25 09:14:04 【问题描述】:

我有一个使用 LZMA2 压缩(压缩级别:超)创建的 7zip 存档。 该档案包含 1,749 个文件,最初的总大小为 661mb。 压缩文件大小为 39mb。

现在我正在尝试使用 C# 从这个存档中提取一个很小的(~200kb'ish)单个文件。

我从 IArchive 获得了相应的 IArchiveEntry(工作相对较快), 但随后调用 IArchiveEntry.WriteToFile(targetPath) 大约需要 33 秒!如果我改为写入内存流,也同样长。 (编辑:当我在压缩级别 = 正常的 7z LZMA2 存档上运行它时,仍然需要 9 秒)

当我在实际的 7zip 应用程序中打开相同的存档并从那里提取相同的文件时,只需要大约 2-3 秒。 我怀疑它是某种多核(7zip)与单核(可能是 SharpCompress?)的事情,但我没有注意到使用 7zip 解压缩期间的任何 CPU 使用率峰值.. 可能它太快以至于无法注意到..

有谁知道使用 SharpCompress 速度如此慢可能是什么问题?我是否可能缺少某些设置或使用了错误的工厂(ArchiveFactory)?

如果没有 - 是否有任何 C# 库在解压缩时可能会更快?

作为参考,这是我如何使用 SharpCompress 提取的草图:

private void Extract()
    
        using(var archive = GetArchive())
        
          var entryPath = /* ... path to entry .. */
          var entry = TryGetEntry(archive, entryPath);
          entry.WriteToFile(some_target_path);
        
    


    private IArchive GetArchive()
    
        string path = /* .. path to my .7z file */;
        return ArchiveFactory.Open(path);
    

    private IArchiveEntry TryGetEntry(IArchive archive, string path)
    
        path = path.Replace("\\", "/");

        foreach (var entry in archive.Entries)
        
            if (!entry.IsDirectory)
            
                if (entry.Key == path)
                    return entry;
            
        

        return null;
    

更新:作为临时解决方案,我现在将 7zip SDK 中的 7zr.exe 包含在我的应用程序中,并在新进程中运行它以提取单个文件,将进程的输出读入二进制流。 与使用 SharpCompress 的约 33 秒相比,这在约 3 秒内即可工作。现在可以工作,但有点难看.. 仍然很好奇为什么 SharpCompress 似乎在那里这么慢

【问题讨论】:

【参考方案1】:

这行是问题

foreach (var entry in archive.Entries)

问题描述here(即,如果有100个文件,它会解压第一个文件100次,第二个文件99次,以此类推)

您需要使用阅读器(仅转发)。请参阅API。 但是那里的示例代码不支持7z。

对于 7z,您可以使用 archive.ExtractAllEntries(),例如。

var reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())

    if (!reader.Entry.IsDirectory)
        reader.WriteEntryToDirectory(extractDir, new ExtractionOptions()  ExtractFullPath = false, Overwrite = true );

会快很多。

【讨论】:

【参考方案2】:

如果您需要所有文件,您也可以这样做:

using var reader = archive.ExtractAllEntries();
reader.WriteAllToDirectory(targetPath, new ExtractionOptions()  ExtractFullPath = true, Overwrite = true );

【讨论】:

以上是关于SharpCompress & LZMA2 7z 存档 - 特定文件的提取速度非常慢。为啥?备择方案?的主要内容,如果未能解决你的问题,请参考以下文章

使用 sharpcompress 创建一个 7zip 存档

使用 SharpCompress 库发布 WinRT 应用程序

使用通用流通过 SharpCompress 创建压缩文件

如何获取 LZMA2 文件 (.xz / liblzma) 的未压缩大小

7zip的lzma和lzma2算法在啥情况下压缩率不一样

如何使用 Sharpcompress .net 从 ZIP 存档中删除单个条目