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

.net 在我的压缩方法中,额外的字符来自哪里?,.net,compression,.net,Compression,我有一个压缩和解压缩方法,用来添加一个额外的空字符。我设法把它修好了,但我不知道为什么修好了,希望有人能给我解释一下 修复程序(-1 from buffer.length,在下一行中): 原始行: System.Buffer.BlockCopy(BitConverter.GetBytes(bytes.Length), 0, gzBuffer, 0, 4) 职能: Private Function Compress(ByVal bytes As Byte()) As Byte() Usi

我有一个压缩和解压缩方法,用来添加一个额外的空字符。我设法把它修好了,但我不知道为什么修好了,希望有人能给我解释一下

修复程序(-1 from buffer.length,在下一行中):

原始行:

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
Private函数压缩(ByVal字节为Byte())为Byte())
将ms用作新内存流()
使用zip作为新的Ionic.Zlib.gzip流(ms、Ionic.Zlib.CompressionMode.Compress、Ionic.Zlib.CompressionLevel.BestCompression,True)
zip.Write(字节,0,字节.长度)
终端使用
//女士职位=0
Dim压缩为Byte()=ms.ToArray()
Dim gzBuffer(compressed.Length+4)作为字节
System.Buffer.BlockCopy(压缩的,0,gzBuffer,4,压缩的.Length)
System.Buffer.BlockCopy(BitConverter.GetBytes(bytes.Length-1)、0、gzBuffer、0、4)
返回缓冲区
终端使用
端函数
私有函数解压缩(ByVal字节为Byte())为Byte()
将ms用作新内存流()
Dim msgLength As Integer=位转换器.ToInt32(字节,0)
ms.Write(字节,4,字节.长度-4)
Dim缓冲区(msgLength)作为字节
女士职位=0
尺寸偏移为整数=0
使用zip作为新的Ionic.Zlib.gzip流(ms,Ionic.Zlib.CompressionMode.decompression)
而偏移量<缓冲区长度-1
offset+=zip.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
不要将内存流读入数组,只需使用
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
Private函数压缩(ByVal字节为Byte())为Byte())
将ms用作新内存流()
女士职位=4
使用zip作为新的GZipStream(ms,CompressionMode.Compress,True)
zip.Write(字节,0,字节.长度)
终端使用
女士职位=0
ms.Write(位转换器.GetBytes(bytes.Length),0,4)
返回ToArray女士()
终端使用
端函数
私有函数解压缩(ByVal字节为Byte())为Byte()
Dim msgLength As Integer=位转换器.ToInt32(字节,0)
将ms用作新内存流(字节)
Dim缓冲区(msgLength-1)作为字节
女士职位=4
尺寸偏移为整数=0
使用zip作为新的GZipStream(ms,CompressionMode.decompresse)
而偏移量<缓冲区长度
offset+=zip.Read(缓冲区、偏移量、缓冲区长度-偏移量)
结束时
终端使用
返回缓冲区
终端使用
端函数

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

如果我必须猜测,我会查看您的
流。读取
代码(它不检查返回值,或者循环使用较大的偏移量和较小的计数,这两种情况通常都是必需的)@marcGravel我的原始代码中偏移量为4,但是我删除了它们,因为我认为这在.Net中是不必要的(我永远不需要通过查看开头有多少空字节来确定块大小)。你能举个例子说明你的意思吗?我不太清楚。你正在用长度整数覆盖压缩数据的前四个字节。我很惊讶你竟然能得到任何东西。@MrShoubs
Read(缓冲区、偏移量、计数)
不保证读取
count
字节;它保证读取0(对于EOF),或者>0和@Guffa,我不知道这四个字节是用来做什么的,所以从我发布的代码中删除了它-我现在编辑了这个问题以显示原始代码。它仍然存在完全相同的问题。+1提供了很好的信息,谢谢,但是第一个代码块创建了一个无限循环,因为偏移量永远不会超过14,buffer.length是15(-1,从长度开始,导致了原始的额外字符问题)。同样使用
将ms用作新的MemoryStream(bytes)
会在解压缩时导致异常“Bad GZip Header”。我已经更新了我的代码以包含您的更改,但我仍然存在原始问题。另一个问题Guffa-您在评论中说我正在用长度整数覆盖压缩数据的前4个字节。。。我看不到我在哪里做的代码行?你能给我指一下吗(用原来的问题代码,不是现在的问题代码)。@Shoubs先生:你发布的原始代码没有覆盖部分数据,我在回答的第一句话中提到了这一点。我不知道你为什么会得到无限循环。你已经删除了原来的问题,所以我的答案不再有任何意义了(另外,在读写内存流时可以使用
Position
,这样就不必创建额外的缓冲区。
Dim buffer(msgLength - 1) As Byte
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