vb.net - 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
我得到的输出是: -
- asciiString 长度:3607
- asciibytes 长度:3607
- 压缩字节长度:3985
解决方案
1.) 这是 2019 年,使用UTF8
,而不是ASCII
;UTF8
99% 兼容,增加了对国际字符(汉字、表情符号、任何您可以输入的内容)的支持。大多数网络浏览器和服务器现在甚至默认使用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
.