2009-11-04 12 views
13

Una matriz serializada BinaryFormatter de 128³ dobles, ocupa 50 MB de espacio. La serialización de una matriz de 128³ struct s con dos campos double ocupa un máximo de 150 MB y más de 20 segundos en procesarse.Alternativas BinaryFormatter

¿Existen alternativas rápidas y sencillas que generen archivos compactos? Mi expectativa es que los ejemplos anteriores tomarían 16 y 32 MB, respectivamente, y menos de dos segundos para procesar. Eché un vistazo a protobuf-net, pero parece que ni siquiera es compatible con struct arrays.

PD: Me disculpo por haber cometido un error al registrar los tamaños de los archivos. La sobrecarga de espacio real con BinaryFormatter no es grande.

Respuesta

4

La serialización significa que los metadatos se agregan para que los datos se puedan deserializar de manera segura, eso es lo que está causando la sobrecarga. Si serializar mismo los datos sin ningún tipo de metadatos, se termina con 16 MB de datos:

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

Por supuesto, esto significa que usted tiene para deserializar los datos por sí mismo también:

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

Si utiliza un BinaryWriter en lugar de un Serializer obtendrá el tamaño deseado (mimimal).
No estoy seguro de la velocidad, pero pruébalo.

En mi sistema, escribir 32MB lleva menos de 0,5 segundos, incluidos Abrir y Cerrar la transmisión.

Usted tendrá que escribir sus propios para bucles para escribir los datos, así:

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

Manual de serialización de hecho puede ser muy rápido y compacto, pero también es propenso a errores y consume mucho tiempo para escribir. Espero algunos gastos generales, pero con BinaryFormatter a menudo no es razonable. –

+0

Puede hacerlo un poco más amigable con genéricos y/o interfaces. Pero comience a agregar meta y se acercará rápidamente a la sobrecarga de los formateadores. –

+0

Spot en Henk. BinaryFormatter funcionará con casi * cualquier cosa *. Debería esperar un mejor rendimiento de algo que hace exactamente lo que necesita y * solo * lo que necesita. –

2

Esto es más de un comentario, pero es demasiado caro para uno ... No estoy capaz de reproducir tus resultados Sin embargo, hay una sobrecarga adicional con la estructura.

Mi prueba:

------------------------------------------------------------------------------- 
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 
------------------------------------------------------------------------------- 

Código:

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

Gracias por la corrección. Mi error. La sobrecarga del espacio no es muy grande. Sin embargo, el tiempo que toma el serializador sigue siendo muy significativo. –

+0

Al igual que comenté en la publicación de Henk, usted está negociando la generalización y la estandarización (BinaryFormatter) por la velocidad de una clase especializada que hace su tarea ** muy bien **. –

+0

Parece que estoy operando demasiado rápido, un orden de magnitud superior a una cantidad razonable. No tiene que tomar tanto tiempo generar el código en la respuesta de Henk Holterman. –