Zip in a zip 打开到未记录的 System.IO.Compression.SubReadStream
Zip within a zip opens to undocumented System.IO.Compression.SubReadStream
我有一个函数用于从 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.InvalidCastException: Unable to cast object of type 'System.IO.Compression.SubReadStream' to type 'System.IO.Compression.DeflateStream'.
我找不到 SubReadStream
的 Microsoft 文档。我想要我的 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: Stream does not support reading.
我检查了 deflateStream.CanRead
是真的。
我发现这不仅发生在 zip 上,而且发生在 zip 中但未压缩的文件上(例如,因为太小)。当然有办法解决这个问题;肯定有人以前遇到过这个。我正在为这个问题悬赏。
这是 SubReadStream
的 .NET source,感谢@Quantic。
所以看起来当将一个 zip 文件存储在另一个 zip 中时,它不会缩小 zip,而是只是将 zip 的内容与其余文件内联,并提供一些信息,这些条目是子 zip 文件。这是有道理的,因为对已经压缩的东西应用压缩是浪费时间。
此 zip 文件在存档中标记为 CompressionMethodValues.Stored
,这导致 .NET 仅 return 它读取的原始流,而不是将其包装在 DeflateStream 中。
如果流不是 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 的行为方式
ZipArchiveEntry.Open() 的 return 类型是 Stream
。一种抽象类型,实际上它可以是 DeflateStream(您会很高兴)、SubReadStream (boo) 或 WrappedStream (boo)。如果他们有一天决定改进 class 并使用 ZopfliStream (boo),你会很不幸。解决方法不好,您正在尝试压缩未压缩的数据 (boo)。
嘘声太多了。
唯一好的 解决方案是更改 OtherFileStreams
成员的类型。我们看不到它,闻起来像 List<DeflateStream>
。它需要是 List<Stream>
.
我有一个函数用于从 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.InvalidCastException: Unable to cast object of type 'System.IO.Compression.SubReadStream' to type 'System.IO.Compression.DeflateStream'.
我找不到 SubReadStream
的 Microsoft 文档。我想要我的 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: Stream does not support reading.
我检查了 deflateStream.CanRead
是真的。
我发现这不仅发生在 zip 上,而且发生在 zip 中但未压缩的文件上(例如,因为太小)。当然有办法解决这个问题;肯定有人以前遇到过这个。我正在为这个问题悬赏。
这是 SubReadStream
的 .NET source,感谢@Quantic。
所以看起来当将一个 zip 文件存储在另一个 zip 中时,它不会缩小 zip,而是只是将 zip 的内容与其余文件内联,并提供一些信息,这些条目是子 zip 文件。这是有道理的,因为对已经压缩的东西应用压缩是浪费时间。
此 zip 文件在存档中标记为 CompressionMethodValues.Stored
,这导致 .NET 仅 return 它读取的原始流,而不是将其包装在 DeflateStream 中。
如果流不是 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 的行为方式
ZipArchiveEntry.Open() 的 return 类型是 Stream
。一种抽象类型,实际上它可以是 DeflateStream(您会很高兴)、SubReadStream (boo) 或 WrappedStream (boo)。如果他们有一天决定改进 class 并使用 ZopfliStream (boo),你会很不幸。解决方法不好,您正在尝试压缩未压缩的数据 (boo)。
嘘声太多了。
唯一好的 解决方案是更改 OtherFileStreams
成员的类型。我们看不到它,闻起来像 List<DeflateStream>
。它需要是 List<Stream>
.