【问题标题】:VB.Net GZip compression is producing too much data and cannot be decodedVB.Net GZip 压缩产生太多数据,无法解码
【发布时间】:2019-06-29 02:13:04
【问题描述】:

我正在尝试使用 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

我得到的输出是:-

  • asciiString 长度:3607
  • asciibytes 长度:3607
  • compressedBytes 长度:3985

【问题讨论】:

  • 是什么让你认为结果是错误的?如果数据不包含压缩算法知道如何压缩的任何模式,则结果不会更小,甚至可能因为压缩算法添加了额外的数据而更大。
  • @Blackwood - 解压器抱怨它无法解压数据。调试让我回到了压缩机。 Base64 通常压缩得很好。如果我捕获 Base64 字符串,将其存储在一个文件(MSDOS 文本格式)中,压缩它 - 它缩小到 2810 字节。
  • 如果压缩数据无法解压缩,这是有关问题的重要信息,我认为您最好编辑问题以包含它。
  • 使用3018字节的源字符串测试此代码,生成的Base64字符串为4024字节。压缩后的 Base64 字符串输出 1418 字节的字节数组。顺便说一句,你没有处理流。你必须这样做。
  • @Jimi - 感谢您测试代码。我将不得不更深入地查看损坏的内容。您知道您使用的 MSBuild 和 Framework 版本吗?

标签: vb.net compression gzipstream


【解决方案1】:

1.) 这是 2019 年,使用 UTF8,而不是 ASCIIUTF8 99% 兼容,增加了对国际字符(汉字、表情符号、任何你可以输入的内容)的支持。大多数 Web 浏览器和服务器现在甚至默认使用 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.Optimal 更改为CompressionMode.Compress

【讨论】:

  • 感谢您的回答,但是,我没有发现您的任何 cmets 相关或有用。
猜你喜欢
  • 2016-12-26
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
  • 2015-02-06
  • 2013-04-25
  • 1970-01-01
  • 2021-06-18
  • 1970-01-01
相关资源
最近更新 更多