[英]C# GZipStream compressing data but decompression returns empty stream
I have the following code:我有以下代码:
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());
}
When I try to compress the string 'Hello World', the compressed Base64 encoded string is 'H4sIAAAAAAACCg=='当我尝试压缩字符串“Hello World”时,压缩后的 Base64 编码字符串为“H4sIAAAAAAAACCg==”
When I try to decompress the Base64 encoded string 'H4sIAAAAAAACCg==' the method Decompress returns an empty string.当我尝试解压缩 Base64 编码字符串 'H4sIAAAAAAAACCg==' 时,方法 Decompress 返回一个空字符串。
You are not getting the correct compressed string.您没有得到正确的压缩字符串。
output.ToArray()
is being called before stream
GZipStream
is flushed, so the contents of output
MemoryStream
would not be the full compressed bytes yet. output.ToArray()
在stream
GZipStream
被刷新之前被调用,所以output
MemoryStream
的内容还不是完整的压缩字节。 You need to add await stream.FlushAsync();
您需要添加
await stream.FlushAsync();
after await input.CopyToAsync(stream);
等待后
await input.CopyToAsync(stream);
. .
The GZipStream
respectively its internal DeflateStream
is designed to implicitly flush its internal buffer on a call to Dispose
(see https://github.com/dotnet/runtime/blob/main/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs ). GZipStream
分别其内部DeflateStream
旨在在调用Dispose
时隐式刷新其内部缓冲区(请参阅https://github.com/dotnet/runtime/blob/main/src/libraries/System.IO.Compression/src/System /IO/Compression/DeflateZLib/DeflateStream.cs )。
For using statements without curly braces, which have been introduced with C# 8.0, the scope is limited by the containing scope.对于使用 C# 8.0 引入的不带花括号的语句,scope 受到包含 scope 的限制。 In this case, the containing scope is the method itself, which means that the object goes out of scope when the method finally exits.
在这种情况下,包含 scope 是方法本身,这意味着当方法最终退出时,object 会从 scope 中退出。 Therefore, the implicit flush from
stream
to output
happens after Convert.ToBase64String(output.ToArray())
.因此,从
stream
到output
的隐式刷新发生在Convert.ToBase64String(output.ToArray())
之后。
To avoid this, we can add curly braces to limit the scope (see example below), or by flushing the stream
explicitly (this is not valid for all .NET versions, see https://github.com/dotnet/runtime/commit/728aa671567d498c1acb6e13cb5cf4f7a883acf7 . To avoid this, we can add curly braces to limit the scope (see example below), or by flushing the
stream
explicitly (this is not valid for all .NET versions, see 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());
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.