4

我有一个用于聚合 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,我会在将流转换为 a 时得到一个例外DeflateStream

System.InvalidCastException:无法将“System.IO.Compression.SubReadStream”类型的对象转换为“System.IO.Compression.DeflateStream”类型。

我无法找到 Microsoft 文档SubReadStream。我希望我的 zip 在一个 zip 中作为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);
    }
}

但我得到一个

System.NotSupportedException:流不支持读取。

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

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

这是.NET 的源代码SubReadStream感谢@Quantic。

4

2 回答 2

5

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

嘘声太多。

唯一好的解决方案是更改您的OtherFileStreams会员类型。我们看不到它,闻起来像List<DeflateStream>。它需要是一个List<Stream>.

于 2016-11-29T20:20:11.627 回答
1

因此,看起来当将 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

您可以将流传递到 ZipArchive,如果它不是 DeflateStream(如果您对里面的文件感兴趣)

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 的行为方式

于 2016-10-28T20:25:26.053 回答