4

我正在使用单声道来膨胀/缩小字节。这是代码:

public static byte[] Inflate(byte[] data)
    {
        using (MemoryStream inStream = new MemoryStream(data))
        {
            using (MemoryStream outStream = new MemoryStream())
            {
                using (DeflateStream decompressStream = new DeflateStream(inStream, CompressionMode.Decompress))
                {
                    decompressStream.CopyTo(outStream);
                }
                return outStream.ToArray();
            }
        }
    }

输入数据为:<789c3dca b9110020 0c04b196 bc9c3f7a 73f11030 281652d1 88b04195 1e742987 2f86258f acdec63d 6dcf0184 560cde> 47bytes。算法是 DEFLATE。

我已经成功地在其他平台上膨胀了相同的数据,但是通过上面的代码,它抛出了以下异常:

System.IO.IOException: Corrupted data ReadInternal
  at System.IO.Compression.DeflateStreamNative.CheckResult (Int32 result, System.String where) [0x00000] in <filename unknown>:0 
  at System.IO.Compression.DeflateStreamNative.ReadZStream (IntPtr buffer, Int32 length) [0x00000] in <filename unknown>:0 
  at System.IO.Compression.DeflateStream.ReadInternal (System.Byte[] array, Int32 offset, Int32 count) [0x00000] in <filename unknown>:0 
  at System.IO.Compression.DeflateStream.Read (System.Byte[] dest, Int32 dest_offset, Int32 count) [0x00000] in <filename unknown>:0 
  at System.IO.Stream.CopyTo (System.IO.Stream destination, Int32 bufferSize) [0x00000] in <filename unknown>:0 
  at System.IO.Stream.CopyTo (System.IO.Stream destination) [0x00000] in <filename unknown>:0 
4

3 回答 3

4

如果您阅读我的评论,您会发现我在 18 小时前遇到了这个问题,虽然问题的答案在您的回答中,但它并不直接明显。在您的答案中有变量集wantRfc1950Header = true,在您的输入流中,前两个字节是 RFC 1950 魔术字节78 9c。需要一个原始 RFC 1951 流,其中System.IO.Compression.DeflateStream省略了这两个字节。我想如果在将前两个字节馈送到充气机之前,您应该能够使用您的初始示例。

不利的一面是,我花了 18 多个小时才发现我需要删除两个字节的数据。从好的方面来说,我更熟悉 zlib 和 Huffman 编码的内部结构。

于 2019-05-28T19:20:01.177 回答
1

最后我用DotNetZip:http ://dotnetzip.codeplex.com解决了这个问题。

public static byte[] Inflate(byte[] data)
    {
        int outputSize = 1024;
        byte[] output = new Byte[ outputSize ];
        bool expectRfc1950Header = true;
        using ( MemoryStream ms = new MemoryStream())
        {
            ZlibCodec compressor = new ZlibCodec();
            compressor.InitializeInflate(expectRfc1950Header);

            compressor.InputBuffer = data;
            compressor.AvailableBytesIn = data.Length;
            compressor.NextIn = 0;
            compressor.OutputBuffer = output;

            foreach (var f in new FlushType[] { FlushType.None, FlushType.Finish } )
            {
                int bytesToWrite = 0;
                do
                {
                    compressor.AvailableBytesOut = outputSize;
                    compressor.NextOut = 0;
                    compressor.Inflate(f);

                    bytesToWrite = outputSize - compressor.AvailableBytesOut ;
                    if (bytesToWrite > 0)
                        ms.Write(output, 0, bytesToWrite);
                }
                while (( f == FlushType.None && (compressor.AvailableBytesIn != 0 || compressor.AvailableBytesOut == 0)) ||
                    ( f == FlushType.Finish && bytesToWrite != 0));
            }

            compressor.EndInflate();

            return ms.ToArray();
        }
    }

    public static byte[] Deflate(byte[] data)
    {
        int outputSize = 1024;
        byte[] output = new Byte[ outputSize ];
        int lengthToCompress = data.Length;

        // If you want a ZLIB stream, set this to true.  If you want
        // a bare DEFLATE stream, set this to false.
        bool wantRfc1950Header = true;

        using ( MemoryStream ms = new MemoryStream())
        {
            ZlibCodec compressor = new ZlibCodec();
            compressor.InitializeDeflate(CompressionLevel.BestCompression, wantRfc1950Header);  

            compressor.InputBuffer = data;
            compressor.AvailableBytesIn = lengthToCompress;
            compressor.NextIn = 0;
            compressor.OutputBuffer = output;

            foreach (var f in new FlushType[] { FlushType.None, FlushType.Finish } )
            {
                int bytesToWrite = 0;
                do
                {
                    compressor.AvailableBytesOut = outputSize;
                    compressor.NextOut = 0;
                    compressor.Deflate(f);

                    bytesToWrite = outputSize - compressor.AvailableBytesOut ;
                    if (bytesToWrite > 0)
                        ms.Write(output, 0, bytesToWrite);
                }
                while (( f == FlushType.None && (compressor.AvailableBytesIn != 0 || compressor.AvailableBytesOut == 0)) ||
                    ( f == FlushType.Finish && bytesToWrite != 0));
            }

            compressor.EndDeflate();

            ms.Flush();
            return ms.ToArray();
        }
    }
于 2014-01-08T07:31:54.173 回答
0

是的,您只能 +2 个字节,但我不确定这是否允许损坏的数据通过或在所有情况下都有效?

   // Note: Caller must Dispose/Close.
    public DataReader ReadCompressedData()
    {
        // TODO: Optimize when using MemoryStream to use GetBuffer?
        var uncompressedSize = ReadInt32();
        var compressedSize = ReadInt32();

        // Consuming 2 bytes for the 78 9C (Sometimes other like 78 DA)
        // Unity / .Net Deflate Stream expects the data to not have this header.
        // I could use the SharpZlib project to get around this or the DotNetZip.
        // https://stackoverflow.com/questions/762614/how-do-you-use-a-deflatestream-on-part-of-a-file
        // http://www.faqs.org/rfcs/rfc1950.html
        // https://stackoverflow.com/questions/20850703/cant-inflate-with-c-sharp-using-deflatestream
        //stream.Position += 2;
        byte[] magic = ReadBytes(2);
        compressedSize -= 2;
        // I wonder if I should check these?

        var compressedData = ReadBytes(compressedSize);
        if (compressedData.Length != compressedSize)
        {
            Debug.LogError("Data read from underlying stream does not match specified size.");
        }

        // Decompress the data in the stream leaving it open.
        // Note: Not sure how to stop DeflateStream gobbling up all data in the stream.
        // using (var ds = new DeflateStream(BaseStream, CompressionMode.Decompress, true))
        // {
        //
        // }

        // Note: We are trusting that the decompressed data will fit completely into uncompressedSize.
        var os = new MemoryStream(uncompressedSize);
        using (var inputStream = new MemoryStream(compressedData))
        {
            using (var ds = new DeflateStream(inputStream, CompressionMode.Decompress))
            {
                ds.CopyTo(os);
            }
        }

        // Reset the stream to the beginning for reading.
        os.Position = 0;
        return new DataReader(os);
    }
于 2019-12-21T12:01:15.633 回答