Zip中的Zip打开到未记录的System.IO.Compression.SubReadStream

本文关键字:Zip System IO Compression SubReadStream 中的 记录 | 更新日期: 2023-09-27 18:15:14

我有一个函数用于从zip存档中聚合流。

private void ExtractMiscellaneousFiles()
{
    foreach (var miscellaneousFileName in _fileData.MiscellaneousFileNames)
    {
        var fileEntry = _archive.GetEntry(miscellaneousFileName);
        if (fileEntry == null)
        {
            throw new ZipArchiveMissingFileException("Couldn't find " + miscellaneousFileName);
        }
        var stream = fileEntry.Open();
        OtherFileStreams.Add(miscellaneousFileName, (DeflateStream) stream);
    }
}

这在大多数情况下都很有效。但是,如果我在zip中有一个zip,则在将流强制转换为DeflateStream时得到一个异常:

系统。无法强制转换System.IO.Compression类型的对象。子读流'到类型' system . io . compression . deflateststream '.

我找不到SubReadStream的Microsoft文档。我想我的拉链内拉链作为一个DeflateStream。这可能吗?如果有,那是怎么回事?

仍然没有成功。我尝试使用以下代码复制@Sunshine的建议:

private void ExtractMiscellaneousFiles()
{
    _logger.Log("Extracting misc files...");
    foreach (var miscellaneousFileName in _fileData.MiscellaneousFileNames)
    {
        _logger.Log($"Opening misc file stream for {miscellaneousFileName}");
        var fileEntry = _archive.GetEntry(miscellaneousFileName);
        if (fileEntry == null)
        {
            throw new ZipArchiveMissingFileException("Couldn't find " + miscellaneousFileName);
        }
        var openStream = fileEntry.Open();
        var deflateStream = openStream;
        if (!(deflateStream is DeflateStream))
        {
            var memoryStream = new MemoryStream();
            deflateStream.CopyTo(memoryStream);
            memoryStream.Position = 0;
            deflateStream = new DeflateStream(memoryStream, CompressionLevel.NoCompression, true);
        }
        OtherFileStreams.Add(miscellaneousFileName, (DeflateStream)deflateStream);
    }
}

但是我得到了

系统。NotSupportedException: Stream does not support reading.

我检查了deflateStream.CanRead,这是真的。

我发现这种情况不仅发生在压缩文件上,也发生在压缩文件中但没有压缩的文件上(例如,因为太小)。当然有办法解决这个问题;肯定有人以前遇到过这种情况。我对这个问题开了一个赏金。

这是SubReadStream的。net源代码,感谢@Quantic。

Zip中的Zip打开到未记录的System.IO.Compression.SubReadStream

ZipArchiveEntry.Open()返回类型为Stream。一个抽象类型,在实践中它可以是一个DeflateStream(你会很高兴),一个SubReadStream (boo)或一个WrappedStream (boo)。如果有一天他们决定改进课程并使用ZopfliStream(嘘声),那你就惨了。解决方法不好,您正在尝试放气未压缩的数据(嘘)。

书太多

唯一好的解决方案是更改OtherFileStreams成员的类型。我们看不见,闻起来像List<DeflateStream>。必须是List<Stream>

因此,看起来当将一个zip文件存储在另一个zip文件中时,它不会压缩zip文件,而只是将zip文件的内容与其他文件内联,其中包含一些信息,即这些条目是子zip文件的一部分。这是有道理的,因为对已经压缩过的东西进行压缩是浪费时间。

这个zip文件在归档文件中被标记为CompressionMethodValues.Stored,这导致。net只返回它读取的原始流,而不是将其包装在DeflateStream中。

来源:https://github.com/dotnet/corefx/blob/master/src/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs#L670

如果它不是一个DeflateStream(如果你对里面的文件感兴趣),你可以把这个流传递给一个ZipArchive。

var stream = entry.Open();
if (!(stream is DeflateStream))
{
    var subArchive = new ZipArchive(stream);
}

或者您可以将流复制到FileStream(如果您想将其保存到磁盘)

var stream = entry.Open();
if (!(stream is DeflateStream))
{
    var fs = File.Create(Path.GetTempFileName());
    stream.CopyTo(fs);
    fs.Close();
}

或者复制到任何你感兴趣的流。

注意:这也是。net 4.6的行为