2014年05月08日

データの圧縮と展開

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その5

■問題 (出題者: 
mattsan さん)
データを圧縮するcompress、展開するdecompressという関数やメソッドなどを書いてください。データはバイト列でもストリームでもそれ以外の形式でもOKです。 圧縮形式は問いませんが、できるだけ一般的なフォーマット(zip,lzhなど)でお願いします。 また、標準以外のライブラリを使う場合には出典の記載をお願いします。 「○○でも実用的な圧縮/展開プログラムがかけるんだぞ!」というのを、ぜひ示してください。

文字列を圧縮、展開するメソッドを作成。 
お題では、一般的なフォーマットとありますが、このコードを書いた当時は、まだ、.NET Framework3.5 だったので、 .NET Framework4.5に追加されたZipArchiveは使ってない。 GZipStream を使ってバイト配列に圧縮。

ZIPファイルについては、メールマガジン「C#プログラミングレッスン」のバックナンバー No.379 を見てください。

■C#で書いたコード 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;


namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            // 文字列をバイト配列に変換します
            string text = @"ある日の暮方の事である。一人の下人(げにん)が、羅生門(らしょうもん)の下で雨やみを待っていた。
広い門の下には、この男のほかに誰もいない。ただ、所々丹塗(にぬり)の剥(は)げた、大きな円柱(まるばしら)に、蟋蟀(きりぎりす)が一匹とまっている。羅生門が、朱雀大路(すざくおおじ)にある以上は、この男のほかにも、雨やみをする市女笠(いちめがさ)や揉烏帽子(もみえぼし)が、もう二三人はありそうなものである。それが、この男のほかには誰もいない。";

            byte[] destination = Compress(text);
            // 圧縮前と圧縮後の長さを比較します
            //Console.WriteLine(source.Length.ToString() + " vs " + ms.Length.ToString());

            // バイト配列を文字列に変換して表示します
            //Console.WriteLine(Encoding.Unicode.GetString(destination));

            string result = Decompress(destination);
            Console.WriteLine(result);
            Console.ReadLine();
        }

        private static string Decompress(byte[] destination) {
            using (MemoryStream ms = new MemoryStream(destination))
            using (GZipStream gzip = new GZipStream(ms, CompressionMode.Decompress)) {
                StringBuilder sb = new StringBuilder();
                byte[] buff = new byte[4096];
                int length = 0;
                while ((length = gzip.Read(buff, 0, buff.Length)) > 0) {
                    sb.Append(Encoding.Unicode.GetString(buff, 0, length));
                }
                return sb.ToString();
            };
        }

        private static byte[] Compress(string text) {
            byte[] source = Encoding.Unicode.GetBytes(text);

            // 入出力用のストリームを生成します
            using (MemoryStream ms = new MemoryStream())
            using (GZipStream gzip = new GZipStream(ms, CompressionMode.Compress)) {

                // ストリームに圧縮するデータを書き込みます
                gzip.Write(source, 0, source.Length);

                // 圧縮されたデータを バイト配列で取得します
                return ms.ToArray();
            }
        }
    }
}


 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/52368956