C# GZipStream 压缩数据但解压 returns 空流
C# GZipStream compressing data but decompression returns empty stream
我有以下代码:
public static async Task<string> Compress(string inputString)
{
var bytes = Encoding.Unicode.GetBytes(inputString);
await using var input = new MemoryStream(bytes);
await using var output = new MemoryStream();
await using var stream = new GZipStream(output, CompressionLevel.SmallestSize);
await input.CopyToAsync(stream);
return Convert.ToBase64String(output.ToArray());
}
public static async Task<string> Decompress(string inputString)
{
var bytes = Convert.FromBase64String(inputString);
await using var output = new MemoryStream();
await using var input = new MemoryStream(bytes);
await using var stream = new GZipStream(input, CompressionMode.Decompress);
await stream.CopyToAsync(output);
await stream.FlushAsync();
return Encoding.Unicode.GetString(output.ToArray());
}
当我尝试压缩字符串'Hello World'时,压缩后的Base64编码字符串是'H4sIAAAAAAACCg=='
当我尝试解压缩 Base64 编码的字符串时 'H4sIAAAAAAACCg==' 方法解压缩 returns 一个空字符串。
您没有得到正确的压缩字符串。 output.ToArray()
在 stream
GZipStream
刷新之前被调用,因此 output
MemoryStream
的内容还不是完整的压缩字节。 await input.CopyToAsync(stream);
.
后需要加上 await stream.FlushAsync();
GZipStream
及其内部 DeflateStream
旨在在调用 Dispose
时隐式刷新其内部缓冲区(参见 https://github.com/dotnet/runtime/blob/main/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs)。
对于C# 8.0 引入的不带花括号的语句,作用域受包含作用域的限制。在这种情况下,包含范围是方法本身,这意味着当方法最终退出时对象超出范围。因此,从 stream
到 output
的隐式刷新发生在 Convert.ToBase64String(output.ToArray())
.
之后
为避免这种情况,我们可以添加花括号来限制范围(参见下面的示例),或者通过显式刷新 stream
(这并非对所有 .NET 版本都有效,参见 https://github.com/dotnet/runtime/commit/728aa671567d498c1acb6e13cb5cf4f7a883acf7.
public static async Task<string> Compress(string inputString)
{
var bytes = Encoding.Unicode.GetBytes(inputString);
await using (var input = new MemoryStream(bytes))
{
await using (var output = new MemoryStream())
{
await using (var stream = new GZipStream(output, CompressionLevel.SmallestSize))
{
await input.CopyToAsync(stream);
}
return Convert.ToBase64String(output.ToArray());
}
}
}
public static async Task<string> Decompress(string inputString)
{
var bytes = Convert.FromBase64String(inputString);
await using (var output = new MemoryStream())
{
await using (var input = new MemoryStream(bytes))
{
await using (var stream = new GZipStream(input, CompressionMode.Decompress))
{
await stream.CopyToAsync(output);
}
}
return Encoding.Unicode.GetString(output.ToArray());
}
}
我有以下代码:
public static async Task<string> Compress(string inputString)
{
var bytes = Encoding.Unicode.GetBytes(inputString);
await using var input = new MemoryStream(bytes);
await using var output = new MemoryStream();
await using var stream = new GZipStream(output, CompressionLevel.SmallestSize);
await input.CopyToAsync(stream);
return Convert.ToBase64String(output.ToArray());
}
public static async Task<string> Decompress(string inputString)
{
var bytes = Convert.FromBase64String(inputString);
await using var output = new MemoryStream();
await using var input = new MemoryStream(bytes);
await using var stream = new GZipStream(input, CompressionMode.Decompress);
await stream.CopyToAsync(output);
await stream.FlushAsync();
return Encoding.Unicode.GetString(output.ToArray());
}
当我尝试压缩字符串'Hello World'时,压缩后的Base64编码字符串是'H4sIAAAAAAACCg=='
当我尝试解压缩 Base64 编码的字符串时 'H4sIAAAAAAACCg==' 方法解压缩 returns 一个空字符串。
您没有得到正确的压缩字符串。 output.ToArray()
在 stream
GZipStream
刷新之前被调用,因此 output
MemoryStream
的内容还不是完整的压缩字节。 await input.CopyToAsync(stream);
.
await stream.FlushAsync();
GZipStream
及其内部 DeflateStream
旨在在调用 Dispose
时隐式刷新其内部缓冲区(参见 https://github.com/dotnet/runtime/blob/main/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs)。
对于C# 8.0 引入的不带花括号的语句,作用域受包含作用域的限制。在这种情况下,包含范围是方法本身,这意味着当方法最终退出时对象超出范围。因此,从 stream
到 output
的隐式刷新发生在 Convert.ToBase64String(output.ToArray())
.
为避免这种情况,我们可以添加花括号来限制范围(参见下面的示例),或者通过显式刷新 stream
(这并非对所有 .NET 版本都有效,参见 https://github.com/dotnet/runtime/commit/728aa671567d498c1acb6e13cb5cf4f7a883acf7.
public static async Task<string> Compress(string inputString)
{
var bytes = Encoding.Unicode.GetBytes(inputString);
await using (var input = new MemoryStream(bytes))
{
await using (var output = new MemoryStream())
{
await using (var stream = new GZipStream(output, CompressionLevel.SmallestSize))
{
await input.CopyToAsync(stream);
}
return Convert.ToBase64String(output.ToArray());
}
}
}
public static async Task<string> Decompress(string inputString)
{
var bytes = Convert.FromBase64String(inputString);
await using (var output = new MemoryStream())
{
await using (var input = new MemoryStream(bytes))
{
await using (var stream = new GZipStream(input, CompressionMode.Decompress))
{
await stream.CopyToAsync(output);
}
}
return Encoding.Unicode.GetString(output.ToArray());
}
}