15

BinaryFormatter でシリアル化された 128³ double の配列は、50 MB のスペースを占有します。2 つのdoubleフィールドを持つ128³のstructの配列をシリアル化すると、150 MB が必要になり、処理に 20 秒以上かかります。

コンパクトなファイルを生成する高速でシンプルな代替手段はありますか? 私の予想では、上記の例はそれぞれ 16 MB と 32 MB を消費し、処理に 2 秒もかかりません。protobuf-net を見てみましたが、構造体配列すらサポートしていないようです。

PS: ファイル サイズの記録に誤りがありましたことをお詫び申し上げます。BinaryFormatter による実際のスペースのオーバーヘッドは大きくありません。

4

3 に答える 3

8

Serializer の代わりに BinaryWriter を使用すると、目的の (最小の) サイズが得られます。
速度についてはわかりませんが、試してみてください。

私のシステムでは、ストリームのオープンとクローズを含めて、32MB の書き込みに 0.5 秒もかかりませんでした。

次のように、データを書き込むために独自のforループを作成する必要があります。

struct Pair
{
    public double X, Y;
}

static void WritePairs(string filename, Pair[] data)
{
    using (var fs = System.IO.File.Create(filename))
    using (var bw = new System.IO.BinaryWriter(fs))
    {
        for (int i = 0; i < data.Length; i++)
        {
            bw.Write(data[i].X);
            bw.Write(data[i].Y);
        }
    }
}

static void ReadPairs(string fileName, Pair[] data)
{
    using (var fs = System.IO.File.OpenRead(fileName))
    using (var br = new System.IO.BinaryReader(fs))
    {
        for (int i = 0; i < data.Length; i++)
        {
            data[i].X = br.ReadDouble();
            data[i].Y = br.ReadDouble();
        }
    }
}
于 2009-11-04T19:30:44.673 に答える
5

シリアル化とは、データを安全に逆シリアル化できるようにメタデータが追加されることを意味します。これがオーバーヘッドの原因です。メタデータなしで自分でデータをシリアル化すると、16 MB のデータになります。

foreach (double d in array) {
   byte[] bin = BitConverter.GetBytes(d);
   stream.Write(bin, 0, bin.Length);
}

これはもちろん、データを自分でデシリアライズする必要があることを意味します。

using (BinaryReader reader = new BinaryReader(stream)) {
   for (int i = 0; i < array.Length; i++) {
      byte[] data = reader.ReadBytes(8);
      array[i] = BitConverter.ToDouble(data, 0);
   }
}
于 2009-11-04T19:29:45.313 に答える
3

これはコメントのようなものですが、1つには多すぎます...私はあなたの結果を再現することができません。ただし、構造体には追加のオーバーヘッドがあります。

私のテスト:

-------------------------------------------------------------------------------
Testing array of structs

Size of double:  8
Size of doubles.bin:  16777244
Size per array item:  8
Milliseconds to serialize:  143
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Testing array of structs

Size of dd struct:  16
Size of structs.bin:  52428991
Size per array item:  25
Milliseconds to serialize:  9678
-------------------------------------------------------------------------------

コード:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Diagnostics;

namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
            TestDoubleArray();
            TestStructArray();
        }

        private static void TestStructArray()
        {

            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            dd[] d1 = new dd[2097152];
            BinaryFormatter f1 = new BinaryFormatter();
            f1.Serialize(File.Create("structs.bin"), d1);

            stopWatch.Stop();

            Debug.WriteLine("-------------------------------------------------------------------------------");
            Debug.WriteLine("Testing array of structs");
            Debug.WriteLine("");
            Debug.WriteLine("Size of dd struct:  " + System.Runtime.InteropServices.Marshal.SizeOf(typeof(dd)).ToString());
            FileInfo fi = new FileInfo("structs.bin");
            Debug.WriteLine("Size of structs.bin:  " + fi.Length.ToString());
            Debug.WriteLine("Size per array item:  " + (fi.Length / 2097152).ToString());
            Debug.WriteLine("Milliseconds to serialize:  " + stopWatch.ElapsedMilliseconds);
            Debug.WriteLine("-------------------------------------------------------------------------------");
        }

        static void TestDoubleArray()
        {
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();

            double[] d = new double[2097152];
            BinaryFormatter f = new BinaryFormatter();
            f.Serialize(File.Create("doubles.bin"), d);

            stopWatch.Stop();

            Debug.WriteLine("-------------------------------------------------------------------------------");
            Debug.WriteLine("Testing array of structs");
            Debug.WriteLine("");
            Debug.WriteLine("Size of double:  " + sizeof(double).ToString());
            FileInfo fi = new FileInfo("test.bin");
            Debug.WriteLine("Size of doubles.bin:  " + fi.Length.ToString());
            Debug.WriteLine("Size per array item:  " + (fi.Length / 2097152).ToString());
            Debug.WriteLine("Milliseconds to serialize:  " + stopWatch.ElapsedMilliseconds);
            Debug.WriteLine("-------------------------------------------------------------------------------");
        }

        [Serializable]
        struct dd
        {
            double a;
            double b;
        }
    }
}
于 2009-11-04T19:40:36.860 に答える