因此,.net没有ZlibStream,所以我尝试使用DeflateStream实现自己的ZlibStream,而.net确实有。DeflateStream显然也不支持使用字典,所以我在ZlibStream中也跳过了这一点。
写作很好,但我的阅读方法有问题。
下面是我的阅读方法:
public override int Read(byte[] buffer, int offset, int count)
{
EnsureDecompressionMode();
if (!_readHeader)
{
// read the header (CMF|FLG|optional DIC)
_readHeader = true;
}
var res = _deflate.Read(buffer, offset, count);
if (res == 0) // EOF
{
// read adler32 checksum
BaseStream.ReadFully(_scratch, 0, 4);
var checksum = (uint)_scratch[0] << 24 |
(uint)_scratch[1] << 16 |
(uint)_scratch[2] << 8 |
(uint)_scratch[3];
if (checksum != _adler32.Checksum)
{
throw new ZlibException("Invalid checksum");
}
}
else
{
_adler32.CalculateChecksum(buffer, offset, res);
}
return res;
}其中:
_scratch是用作临时缓冲区的byte[4]。_deflate是DeflateStream。Zlib的格式是CMF|FLG|optional DICT|compressed data|adler32|。因此,当到达adler32时,我需要一种停止阅读的方法。最初,我以为DeflateStream会在它完成后返回EOF,但结果是它一直读到底层流的EOF。因此,它还读取adler32,好像它是压缩的数据。因此,当我试图从adler32块内的BaseStream读取if时,会引发EOF异常。
那么,我如何使DeflateStream停止读取adler32,就好像它是压缩的数据,而不是EOF,或者做一些类似的事情,这样我就可以不用压缩从BaseStream读取adler32了?
发布于 2017-09-15 12:06:49
既然文件的大小是固定的,你就不能在base.Length - typeof(int)上停下来吗?必要时调整读缓冲区,然后读取未压缩校验和.
有点像:
public override int Read(byte[] buffer, int offset, int count)
{
// read header...
int res = -1;
if (base.Position + count - offset > base.Length)
{
// EOF, skip the last four bytes (adler32) and read them without decompressing
res = _deflate.Read(buffer, offset, count - sizeof(int));
}
else
{
res = _deflate.Read(buffer, offset, count);
}
// continue processing the data
}未测试
发布于 2022-03-02 10:16:00
通过源代码这里,DeflateStream读取8K块中的输入数据:-/,所以如果您的输入文件很小,它看起来就像是在读取文件的末尾,
但是,DeflateStream实例有一个私有成员_inflater,其中有一个私有成员_zlibStream,该成员有一个属性AvailIn,该属性返回输入缓冲区中可用的字节数。IOW,这是读取的字节数,所以通过使用反射获取这些私有部分,我们可以将文件指针向后移动那么多字节,将其返回到应该保留的位置,即刚刚过了压缩数据的末尾。
这段代码是F#,但是应该清楚地知道发生了什么:
// zstream is the DeflateStream instance
let inflater = typeof<DeflateStream>.GetField( "_inflater", BindingFlags.NonPublic ||| BindingFlags.Instance ).GetValue( zstream )
let zlibStream = inflater.GetType().GetField( "_zlibStream", BindingFlags.NonPublic ||| BindingFlags.Instance ).GetValue( inflater )
let availInMethod = zlibStream.GetType().GetProperty( "AvailIn" ).GetMethod
let availIn: uint32 = unbox( availInMethod.Invoke( zlibStream, null ) )
// inp is the input file
inp.Seek( -(int64 availIn), SeekOrigin.Current ) |> ignorehttps://stackoverflow.com/questions/46238944
复制相似问题