2009-11-04 4 views
13

BinaryFormatter - 128 입방의 직렬 배열은 50MB의 공간을 차지합니다. 두 개의 double 필드가있는 12838 구조체의 배열을 직렬화하면 처리 할 때 150MB와 20 초 이상이 소요됩니다.BinaryFormatter 대안

간단한 파일을 생성하는 빠른 대안이 있습니까? 내 기대는 위의 예는 각각 16MB와 32MB를 처리하고 2 초 이내에 처리하는 것입니다. protobuf-net을 살펴 봤지만 구조체 배열을 지원하지 않는 것으로 보입니다.

추신 : 파일 크기를 잘못 기록해 죄송합니다. BinaryFormatter의 실제 공간 오버 헤드는 크지 않습니다.

답변

4

직렬화 란 메타 데이터가 추가되어 데이터를 안전하게 deserialize 할 수 있기 때문에 오버 헤드가 발생하는 것입니다. 물론 이렇게하면 데이터도 자신을 역 직렬화해야 함을 의미

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

: 당신이 어떤 메타 데이터없이 데이터를 직접 직렬화하는 경우 데이터 16MB의와 끝까지

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); 
    } 
} 
7

당신이 사용하는 경우 serializer 대신 BinaryWriter를 사용하면 원하는 크기 (mimimal)를 얻을 수 있습니다.
속도에 대해서는 잘 모르겠지만 시도해보십시오.

내 시스템에서 32MB를 기록하는 데는 스트림 열기 및 닫기를 포함하여 0.5 초 미만이 소요됩니다.

당신은 다음과 같이 데이터를 기록하기 위해 자신의 에 대한 루프를 작성해야합니다

:

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(); 
     } 
    } 
} 
+2

수동 직렬화가 실제로 매우 빠르고 컴팩트 될 수 있지만, 또한 오류가 발생하는 경향과 시간이 많이 소요 작성하는 것입니다. 오버 헤드가 예상되지만, BinaryFormatter를 사용하면 종종 불합리합니다. –

+0

제네릭 및/또는 인터페이스로 좀 더 친숙하게 만들 수 있습니다. 그러나 메타를 추가하기 시작하면 포매터의 오버 헤드에 신속하게 접근하게됩니다. –

+0

헨크 스팟. BinaryFormatter는 about * anything *과 함께 작동합니다. 당신은 당신이 필요로하는 것과 당신이 필요로하는 것만을 정확하게 무언가로하여 더 나은 성과를 기대해야합니다. –

2

이 주석의 더하지만이 방법은 하나 너무 많이의 ... 아니에요 결과를 재현 할 수 있어야합니다. 그러나 구조체에는 약간의 추가 오버 헤드가 있습니다.

내 테스트 :

------------------------------------------------------------------------------- 
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; 
     } 
    } 
} 
+0

수정 해 주셔서 감사합니다. 내 잘못이야. 공간 오버 헤드는 그다지 크지 않습니다. 그러나 시리얼 라이저가 걸리는 시간은 여전히 ​​매우 중요합니다. –

+0

Henk의 게시물에 댓글을 달았음에도 불구하고, 당신은 일반화 및 표준화 (BinaryFormatter)를 통해 전문 수업의 속도에 대해 한 가지 작업 ** **을 잘 처리하고 있습니다 **. –

+0

나는 너무 많은 속도로 거래하고있는 것처럼 보입니다. 합리적인 금액을 초과하는 규모입니다. 헨크 홀터 먼 (Henk Holterman)의 대답에서이 코드를 생성하는 데 오랜 시간이 걸릴 필요는 없습니다. –