额外字符在我的压缩方法中来自哪里?

时间:2011-10-21 11:27:41

标签: .net compression

我有一个压缩和解压缩方法,用于添加一个额外的空字符。我设法解决了这个问题,但我不确定为什么固定有效,希望有人能解释一下。

修复(以下行中的buffer.length为-1):

System.Buffer.BlockCopy(BitConverter.GetBytes(bytes.Length - 1), 0, gzBuffer, 0, 4)

原帖:

System.Buffer.BlockCopy(BitConverter.GetBytes(bytes.Length), 0, gzBuffer, 0, 4)

功能:

Private Function Compress(ByVal bytes As Byte()) As Byte()
    Using ms As New MemoryStream()

        Using zip As New Ionic.Zlib.GZipStream(ms, Ionic.Zlib.CompressionMode.Compress, Ionic.Zlib.CompressionLevel.BestCompression, True)
            zip.Write(bytes, 0, bytes.Length)
        End Using

        //ms.Position = 0
        Dim compressed As Byte() = ms.ToArray()

        Dim gzBuffer(compressed.Length + 4) As Byte
        System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length)
        System.Buffer.BlockCopy(BitConverter.GetBytes(bytes.Length -1), 0, gzBuffer, 0, 4)

        Return gzBuffer
    End Using
End Function

Private Function DeCompress(ByVal bytes As Byte()) As Byte()

    Using ms As New MemoryStream()
        Dim msgLength As Integer = BitConverter.ToInt32(bytes, 0)
        ms.Write(bytes, 4, bytes.Length - 4)

        Dim buffer(msgLength) As Byte

        ms.Position = 0
        Dim offset As Integer = 0
        Using zip As New Ionic.Zlib.GZipStream(ms, Ionic.Zlib.CompressionMode.Decompress)
            While offset < buffer.Length - 1
                offset += zip.Read(buffer, offset, buffer.Length - offset)
            End While
        End Using

        Return buffer
    End Using
End Function

1 个答案:

答案 0 :(得分:2)

这样更好,现在长度不会覆盖部分压缩数据。

现在您的问题是您没有正确使用Stream.Read方法。该方法返回读取的字节数,可以小于请求的字节数,因此您必须获取该返回值并重复读取,直到获得所有数据:

Dim offset as Integer = 0
Using zip As New Ionic.Zlib.GZipStream(ms, Ionic.Zlib.CompressionMode.Decompress)
  Do While offset < buffer.Length
    offset += zip.Read(buffer, offset, buffer.Length - offset)
  Loop
End Using

此外,不是将字节数组写入内存流,只需从数组中创建内存流:

Using ms As New MemoryStream(bytes)

不要将内存流读入数组,只需使用ToArray方法:

Dim compressed As Byte() = ms.ToArray()

编辑:

代码中的一次性问题是由于如何使用最高索引而不是大小在VB中创建数组,因此应使用以下命令创建缓冲区:

Dim buffer(msgLength - 1) As Byte

在读取和写入内存流时使用Position属性可以避免创建额外的缓冲区:

Private Function Compress(ByVal bytes As Byte()) As Byte()
  Using ms As New MemoryStream()
    ms.Position = 4
    Using zip As New GZipStream(ms, CompressionMode.Compress, True)
      zip.Write(bytes, 0, bytes.Length)
    End Using
    ms.Position = 0
    ms.Write(BitConverter.GetBytes(bytes.Length), 0, 4)
    Return ms.ToArray()
  End Using
End Function

Private Function DeCompress(ByVal bytes As Byte()) As Byte()
  Dim msgLength As Integer = BitConverter.ToInt32(bytes, 0)
  Using ms As New MemoryStream(bytes)
    Dim buffer(msgLength - 1) As Byte
    ms.Position = 4
    Dim offset As Integer = 0
    Using zip As New GZipStream(ms, CompressionMode.Decompress)
      While offset < buffer.Length
        offset += zip.Read(buffer, offset, buffer.Length - offset)
      End While
    End Using
    Return buffer
  End Using
End Function

(注意:此代码使用标准.NET GZipStream。)