首页 > 解决方案 > VB.Net GZip 压缩产生太多数据,无法解码

问题描述

我正在尝试使用 GZip 压缩一个 ascii 字符串(base64),但是,它会产生更多的数据而不是更少的数据。任何人都可以帮忙吗?

这是一个旧项目,我仅限于编译器和框架版本。我已经尝试过 MSBuild 2.0、3.5 和 4.0 - 都产生相同的错误结果。

Imports System.IO.Compression

Private Function GZipString(ByVal asciiString As String) as Byte()

    Debug.Print ("asciiString length : {0}", asciiString.Length )
    Dim asciibytes As Byte() = Encoding.ASCII.GetBytes(asciiString)
    Debug.Print ("asciibytes length : {0}", asciibytes.Length )

    'GZip the string
    Dim ms As New MemoryStream()
    Dim gzips As New GZipStream(ms, CompressionMode.Compress)
    gzips.Write(asciibytes, 0, asciibytes.Length)
    gzips.Close()

    GZipString = ms.ToArray
    ms.Close()
    Debug.Print ("compressedBytes length : {0}", GZipString.Length )

End Function

我得到的输出是: -

标签: vb.netcompressiongzipstream

解决方案


1.) 这是 2019 年,使用UTF8,而不是ASCIIUTF899% 兼容,增加了对国际字符(汉字、表情符号、任何您可以输入的内容)的支持。大多数网络浏览器和服务器现在甚至默认使用UTF8编码格式(多年来一直如此)。您通常应该避免ASCII使用,除非您正在使用需要它的遗留软件......(即使那样,也只适用于与该遗留系统对话的部分代码!)

2.) 作为参考,压缩字符串并不总是会导致更少的字节;尤其是小弦;一个 3600 个字符的字符串虽然应该绝对压缩(除非它包含完全随机的垃圾,否则该长度的人工键入的纯文本字符串肯定应该压缩)。

3.)您应该正确处理对象(通过using语句)。不这样做会导致资源和/或内存泄漏。

4.)您的压缩或解压缩代码错误;并且GZipStream可能非常挑剔;所以,我已经包含了适用于C#VB.NET以下的测试代码。

C#版本:

static void Main(string[] args)
{
    var input = string.Join(" ", args);
    var compressedBytes = CompressString(input);
    var dec = DecompressString(compressedBytes);

    Console.WriteLine("Input Length        = " + input.Length);                          // 537
    Console.WriteLine("Uncompressed Size   = " + Encoding.UTF8.GetBytes(input).Length);  // 539
    Console.WriteLine("Compressed Size     = " + compressedBytes.Length);                // 354 (smaller!)
    Console.WriteLine("Decompressed Length = " + dec.Length);                            // 537 (same size!)
    Console.WriteLine("Roundtrip Successful: " + (input == dec));                        // True
}

public static string DecompressString(byte[] bytes)
{
    using (var ms = new MemoryStream(bytes))
    using (var ds = new GZipStream(ms, CompressionMode.Decompress))
    using (var sr = new StreamReader(ds))
    {
        return sr.ReadToEnd();
    }
}

public static byte[] CompressString(string input)
{
    using (var ms = new MemoryStream())
    using (var cs = new GZipStream(ms, CompressionLevel.Optimal))
    {
        var bytes = Encoding.UTF8.GetBytes(input);
        cs.Write(bytes, 0, bytes.Length);

        // *REQUIRED* or last chunk will be omitted. Do NOT call any other close or
        // flush method.
        cs.Close();

        return ms.ToArray();
    }
}

VB.NET 版本

(恶心,我觉得很脏):

Sub Main(args As String())
    Dim input As String = String.Join(" ", args)
    Dim compressedBytes As Byte() = CompressString(input)
    Dim dec As String = DecompressString(compressedBytes)

    Console.WriteLine("Input Length        = " & input.Length)                          ' 537
    Console.WriteLine("Uncompressed Size   = " & Encoding.UTF8.GetBytes(input).Length)  ' 539
    Console.WriteLine("Compressed Size     = " & compressedBytes.Length)                ' 354 (smaller!)
    Console.WriteLine("Decompressed Length = " & dec.Length)                            ' 537 (same size!)
    Console.WriteLine("Roundtrip Successful: " & (input = dec).ToString())              ' True
End Sub

Public Function DecompressString(ByVal bytes As Byte()) As String

    Using ms = New MemoryStream(bytes)
        Using ds = New GZipStream(ms, CompressionMode.Decompress)
            Using sr = New StreamReader(ds)

                Return sr.ReadToEnd()

            End Using
        End Using
    End Using

End Function

Public Function CompressString(input As String) As Byte()

    Using ms = New MemoryStream
        Using cs = New GZipStream(ms, CompressionLevel.Optimal)

            Dim bytes As Byte() = Encoding.UTF8.GetBytes(input)
            cs.Write(bytes, 0, bytes.Length)

            ' *REQUIRED* Or last chunk will be omitted. Do Not call any other close Or
            ' flush method.
            cs.Close()

            Return ms.ToArray()

        End Using
    End Using

End Function

编辑:

对于 .NET 3.5,这仍然有效(并产生一个更小的对象;虽然没有 4.8 小,但它只压缩到 497 字节,而不是我的示例数据的 354 字节)。

您只需要更改CompressionLevel.OptimalCompressionMode.Compress.


推荐阅读