[C#]シリアライズしたバイナリデータを圧縮解凍する方法
.Net Freamework 2.0から、System.IO.Compressionが追加されていて、DeflateStream(rfc1951), GZipStream(rfc1952)が使用できる。
シリアライズはBinaryFormatterを使えばいい。簡単に書こうとすると、以下のよーな感じになる。
/// <summary> /// オブジェクトを圧縮して書き込み /// </summary> /// <param name="filePath"></param> /// <param name="obj"></param> public void WriteWithCompress(string filePath, object obj) { using (Stream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { using (DeflateStream ds = new DeflateStream(stream, CompressionMode.Compress, true)) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(ds, obj); } } }
このソースを.Net Freamework 2.0(VisualStudio2005)で動作させてみると、出力サイズが大して圧縮されていないことに気づくと思う。ところが、.Net Freamework 3.0(VisualStudio2008)で動作させるとサイズは半分以下になる。
この違いは、恐らく2.0のバグが3.0で改善されたとか、そんなところじゃないかと思われる。根拠はないが。
じゃあ2.0では使い物にならないのかというと、そういうわけでもない。
MemoryStreamを使用して、逐一バッファに保持すればいい。
/// <summary> /// オブジェクトを圧縮して書き込み /// </summary> /// <param name="filePath"></param> /// <param name="obj"></param> public void WriteWithCompress(string filePath, object obj) { byte[] buffer; using (MemoryStream ms = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); buffer = ms.ToArray(); } using (MemoryStream ms = new MemoryStream()) { using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress, true)) { ds.Write(buffer, 0, buffer.Length); } buffer = ms.ToArray(); } using (Stream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { stream.Write(buffer, 0, buffer.Length); } }
これで2.0, 3.0で同様の結果が得られる。
読み込みについては、バージョン関係なく以下のように。
/// <summary> /// 圧縮されたオブジェクトを解凍して読み込み /// </summary> /// <param name="filePath"></param> /// <returns></returns> public object ReadWithDecompress(string filePath) { object obj; using (Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { using (DeflateStream ds = new DeflateStream(stream, CompressionMode.Decompress)) { IFormatter formatter = new BinaryFormatter(); obj = formatter.Deserialize(ds); } } return obj; }
ちなみに、GZipStreamを使いたい場合は、DeflateStreamをGZipStreamに書き換えるだけでOKだ。