首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C# MemoryStream & GZipInputStream:无法.Read超过256字节

C# MemoryStream & GZipInputStream:无法.Read超过256字节
EN

Stack Overflow用户
提问于 2019-10-10 00:00:52
回答 2查看 355关注 0票数 2

我在使用SharpZipLib的GZipInputStream编写未压缩的GZIP流时遇到了问题。我似乎只能获得256个字节的数据,其余的数据没有被写入,并被置零。已检查压缩流(compressedSection),并且所有数据都在那里(1500+字节)。解压缩过程的代码片段如下:

代码语言:javascript
复制
int msiBuffer = 4096;
using (Stream msi = new MemoryStream(msiBuffer))
{
    msi.Write(compressedSection, 0, compressedSection.Length);
    msi.Position = 0;
    int uncompressedIntSize = AllMethods.GetLittleEndianInt(uncompressedSize, 0); // Gets little endian value of uncompressed size into an integer

    // SharpZipLib GZip method called
    using (GZipInputStream decompressStream = new GZipInputStream(msi, uncompressedIntSize))
    {
        using (MemoryStream outputStream = new MemoryStream(uncompressedIntSize))
        {
            byte[] buffer = new byte[uncompressedIntSize];
            decompressStream.Read(buffer, 0, uncompressedIntSize); // Stream is decompressed and read         
            outputStream.Write(buffer, 0, uncompressedIntSize);
            using (var fs = new FileStream(kernelSectionUncompressed, FileMode.Create, FileAccess.Write))
            {
                fs.Write(buffer, 0, buffer.Length);
                fs.Close();
            }
            outputStream.Close();
        }
        decompressStream.Close();

所以在下面的代码片段中:

1)传入压缩段,准备解压。

2)未压缩输出的预期大小(以2字节的小端值存储在文件的头部中)通过一个方法将其转换为整数。因为它不是压缩的GZIP文件的一部分,所以头文件在前面被删除了。

3) SharpLibZip的GZIP流是使用压缩文件流(msi)和等于int uncompressedIntSize的缓冲区声明的(也使用静态值4096进行了测试)。

4)我设置了一个MemoryStream来处理将输出写入文件,因为GZipInputStream没有读/写功能;它将预期的解压缩文件大小作为参数(容量)。

5)读/写流需要byte[]数组作为第一个参数,因此我设置了一个byte[]数组,该数组具有足够的空间来获取解压缩后的输出的所有字节(在本例中为3584字节,派生自uncompressedIntSize)。

6) int GzipInputStream decompressStream使用.Read,缓冲区作为第一个参数,从偏移量0开始,使用uncompressedIntSize作为计数。检查这里的参数,buffer数组仍然有3584字节的容量,但只提供了256字节的数据。其余的都是零。

看起来.Read的输出被限制到256字节,但是我不确定在哪里。流中是否有我遗漏的东西,或者这是.Read的一个限制?

EN

回答 2

Stack Overflow用户

发布于 2019-10-10 00:10:17

从流读取时需要循环;懒惰的方式可能是:

代码语言:javascript
复制
decompressStream.CopyTo(outputStream);

(但这不能保证在uncompressedIntSize字节之后停止-它将尝试读取到decompressStream的末尾)

一个更手动的版本(遵守强制的长度限制)将是:

代码语言:javascript
复制
const int BUFFER_SIZE = 1024; // whatever
var buffer = ArrayPool<byte>.Shared.Rent(BUFFER_SIZE);
try
{
    int remaining = uncompressedIntSize, bytesRead;
    while (remaining > 0 && // more to do, and making progress
        (bytesRead = decompressStream.Read(
        buffer, 0, Math.Min(remaining, buffer.Length))) > 0)
    {
        outputStream.Write(buffer, 0, bytesRead);
        remaining -= bytesRead;
    }
    if (remaining != 0) throw new EndOfStreamException();
}
finally
{
    ArrayPool<byte>.Shared.Return(buffer);
}
票数 2
EN

Stack Overflow用户

发布于 2019-10-10 18:58:22

这个问题被证明是我在前面的代码中犯下的一个疏忽:

我正在处理的文件有27个部分,它们都是GZipped的,但每个部分都有一个头,如果GZipInput流命中其中任何一个,就会破坏Gzip解压缩。当打开基础文件时,每次都是从头开始(调整6以避免第一个头部),而不是进入下一个post-head偏移量:

brg.BaseStream.Seek(6,SeekOrigin.Begin);

而不是:

brg.BaseStream.Seek(absoluteSectionOffset,SeekOrigin.Begin);

这意味着提取的压缩数据是第一个无标题部分+第二个部分及其标题的一部分。由于第一部分的长度为256字节长,没有其头部,因此该部分已被GZipInput流正确地解压缩。但在那之后是6个字节的头,这打破了它,导致输出的其余部分是00s。

发生这种情况时,GZipInput流没有抛出显式错误,所以我错误地假设原因是流中保留了前一遍中的数据的.Read或其他东西。很抱歉给你添麻烦了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58308066

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档