7

バイナリシリアル化する必要があるクラスがあります。クラスには、以下の 1 つのフィールドが含まれます。

private T[,] m_data;

これらの多次元配列は、かなり大きく (数十万の要素)、任意のプリミティブ型にすることができます。オブジェクトで標準の .net シリアライゼーションを試したところ、ディスクに書き込まれたファイルが大きく、.net は要素の型に関する多くの繰り返しデータを格納していて、おそらく効率的に実行できなかったと思います。

カスタムシリアライザーを探しましたが、多次元の汎用配列を扱うものは見たことがありません。また、シリアライズ後のメモリ ストリームのバイト配列に対する組み込みの .net 圧縮を試してみましたが、期待したほど速く圧縮されませんでした。

私の質問は、カスタム シリアライザーを作成して、この配列を適切な型に最適にシリアル化する必要がありますか (これは少し難しいようです)、または標準の .net シリアル化を使用して圧縮を追加する必要がありますか?

最善のアプローチに関するアドバイス、または多次元ジェネリック配列のシリアル化に取り組む方法を示すリソースへのリンクをいただければ幸いです。前述のように、私が見つけた既存の例はそのような構造をサポートしていません。

4

4 に答える 4

5

これが私が思いついたものです。以下のコードは int[1000][10000] を作成し、BinaryFormatter を使用して 2 つのファイル (1 つは圧縮され、もう 1 つは圧縮されていない) に書き込みます。

圧縮されたファイルは 1.19 MB (1,255,339 バイト) で、解凍されたファイルは 38.2 MB (40,150,034 バイト) です。

        int width = 1000;
        int height = 10000;
        List<int[]> list = new List<int[]>();
        for (int i = 0; i < height; i++)
        {
            list.Add(Enumerable.Range(0, width).ToArray());
        }
        int[][] bazillionInts = list.ToArray();
        using (FileStream fsZ = new FileStream("c:\\temp_zipped.txt", FileMode.Create))
        using (FileStream fs = new FileStream("c:\\temp_notZipped.txt", FileMode.Create))
        using (GZipStream gz = new GZipStream(fsZ, CompressionMode.Compress))
        {
            BinaryFormatter f = new BinaryFormatter();
            f.Serialize(gz, bazillionInts);
            f.Serialize(fs, bazillionInts);
        }

これを行うためのより良い/簡単な方法は考えられません。圧縮されたバージョンはかなりきついです。

BinaryFormatter + GZipStream を使用します。何かをカスタムするのはまったく楽しくありません。


[MG による編集] 編集によって気分を害されないことを願っていますが、均一に繰り返される Range(0,width) は物事を大きく歪めています。への変更:

        int width = 1000;
        int height = 10000;
        Random rand = new Random(123456);
        int[,] bazillionInts = new int[width, height];
        for(int i = 0 ; i < width;i++)
            for (int j = 0; j < height; j++)
            {
                bazillionInts[i, j] = rand.Next(50000);
            }

そして試してみてください。temp_notZipped.txt40MB、temp_zipped.txt62MB で表示されます。あまり魅力的ではない...

于 2008-10-22T00:00:58.100 に答える
0

「大きい」の定義を教えてください。1000x10000xint の例 (別の投稿) は 40Mb です。1000x10000x4 バイト (=int) は 38MB です。オーバーヘッドが進むにつれて、それはひどいものではありません。

T はどのようなデータである可能性が高いですか? プリミティブだけ?おそらくprotobuf-netを編集して長方形の配列をサポートできると考えています*が、ある種のワイヤ互換性を維持するには、おそらく要素ごとにヘッダー (1 バイト) が必要です。つまり、1000x10000 の例では 9MB のオーバーヘッドが必要です。

floatこれはおそらく、 、 などのようなものには価値がありませんdouble(「プロトコルバッファー」の下に逐語的に保存されるため) - しかし、int単純に int をパックする方法により、節約できる可能性があります... (特に、小さい側にある[大きさ])。最後に、T が実際に etc のようなオブジェクトである場合、オブジェクトのパッキングが非常に優れているため、バイナリ シリアル化よりもはるかPersonに優れているはずです。

長方形の配列で靴べらを作るのは簡単なことではありませんが、これがあなたが試してみたいものであるかどうか教えてください.

*: 「プロトコル バッファ」仕様ではサポートされていないため、現時点ではサポートされていませんが、ハックすることはできます...

于 2008-10-22T05:56:28.663 に答える
0

型に関する非常に多くのデータが必要な理由は、T の配列は任意の型である可能性があるためですが、より具体的には、T は SomeBaseClass 型である可能性があり、その配列に SomeDerivedClass を格納することができ、デシリアライザーはこれを知っています。

しかし、他の人が指摘しているように、この冗長データは圧縮の良い候補になります。

于 2009-09-25T14:54:08.703 に答える
0

コード長と出力サイズの最適な比率は、BitConverter を使用して配列をエンコードし、すべての要素をコンパクトなバイナリ形式に変換することです。手動ですが、.NET バイナリ シリアル化と比較して 80 ~ 90% のスペースを節約できます。

于 2008-10-21T22:14:04.977 に答える