LoginSignup
1
1

.Net 6以降のC#のGZipStreamの挙動変更について

Last updated at Posted at 2023-02-07

概要

GZipStreamの挙動が変更されており、一定サイズ以上のデータが解凍できなくなった
そこで正しい解凍方法の共有する

変更内容

GZipStream.Readが指定したバイト数を読み込むとは限らなくなった

コード

変更前

before.cs
static byte[] Decode(byte[] src)
{
	var length = BitConverter.ToInt32(src, src.Length - 4);
	var bytes = new byte[length];
	using var ms = new MemoryStream(src);
	using var gs = new GZipStream(ms, CompressionMode.Decompress);
	gs.Read(bytes, 0, bytes.Length);

	return bytes;
}

変更後

after.cs
static byte[] Decode(byte[] src)
{
	var length = BitConverter.ToInt32(src, src.Length - 4);
	var bytes = new byte[length];
	using var ms = new MemoryStream(src);
	using var gs = new GZipStream(ms, CompressionMode.Decompress);
	int offset = 0;
	while (offset < bytes.Length)
	{
		var readSize = gs.Read(bytes, offset, bytes.Length - offset);
		if (readSize == 0) break;
		offset += readSize;
	}

	return bytes;
}

比較

- 	gs.Read(bytes, 0, bytes.Length);
+ 	int offset = 0;
+ 	while (offset < bytes.Length)
+	{
+		var readSize = gs.Read(bytes, offset, bytes.Length - offset);
+		if (readSize == 0) break;
+		offset += readSize;
+	}

余談

gzipファイルは後ろ4バイトにValidate用の解凍後のサイズが入っている
こちらを使うことで、あらかじめ解凍後のサイズのバッファを用意して不要なリサイズを避ける

var length = BitConverter.ToInt32(src, src.Length - 4);

.Net 7からの新機能

Stream.ReadExactlyを使うことで、必ず指定したバイト数分読むことが保証されるようになった
公式ドキュメント

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1