Pregunta

Tengo una clase que necesito para serializar binario. La clase contiene un campo como el siguiente:

private T[,] m_data;

Estas matrices multidimensionales pueden ser bastante grandes (cientos de miles de elementos) y de cualquier tipo primitivo. Cuando probé la serialización .net estándar en un objeto, el archivo escrito en el disco era grande y creo que .net está almacenando una gran cantidad de datos repetidos sobre los tipos de elementos y posiblemente no tan eficientemente como podría hacerse.

Busqué serializadores personalizados, pero no he visto ninguno que se ocupe de arreglos genéricos multidimensionales. También he experimentado con la compresión .net incorporada en una matriz de bytes de la secuencia de memoria luego de serializar con cierto éxito, pero no tan rápido / comprimido como esperaba.

Mi pregunta es, ¿debería intentar y escribir un serializador personalizado para serializar de manera óptima esta matriz para el tipo apropiado (esto parece un poco desalentador), o debo usar la serialización .net estándar y agregar compresión?

Cualquier consejo sobre el mejor enfoque sería más apreciado, o enlaces a recursos que muestran cómo abordar la serialización de una matriz genérica multidimensional, como se menciona ejemplos existentes he encontrado que no son compatibles con dichas estructuras.

¿Fue útil?

Solución

Esto es lo que se me ocurrió. El siguiente código crea un int [1000] [10000] y lo escribe utilizando el BinaryFormatter en 2 archivos, uno comprimido y otro no.

El archivo comprimido es de 1.19 MB (1.255.339 bytes) Sin comprimir es de 38.2 MB (40,150,034 bytes)

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

No puedo pensar en una forma mejor / fácil de hacer esto. La versión con cremallera es bastante justa.

Iría con el BinaryFormatter + GZipStream. Hacer algo personalizado no sería divertido en absoluto.


[editar por MG] Espero que no se sienta ofendido por una edición, pero el rango repetido uniforme (0, ancho) está sesgando las cosas enormemente; cambiar a:

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

Y pruébalo; verá temp_notZipped.txt a 40MB, temp_zipped.txt a 62MB. No es tan atractivo ...

Otros consejos

La mejor relación entre la longitud del código y el tamaño de salida sería codificar su matriz utilizando BitConverter, convirtiendo todos los elementos en su formato binario compacto. Es manual, lo sé, pero ahorrará un 80-90% de espacio en comparación con la serialización binaria .NET.

¿Puedes definir " grande " ;? El ejemplo de 1000x10000xint (otra publicación) sale a 40Mb; y 1000x10000x4 bytes (= int) es de 38MB. Como pasan los gastos generales, eso no es terrible.

¿Qué tipo de datos es probable que sea T? ¿Solo primativos? Estoy pensando que probablemente podría editar protobuf-net para admitir matrices rectangulares < código> * - pero para mantener algún tipo de compatibilidad de cable, probablemente necesitaríamos un encabezado (un byte) por elemento - es decir, 9MB de sobrecarga para el ejemplo 1000x10000.

Probablemente no valga la pena para cosas como float , double , etc. (ya que se almacenan literalmente en " búferes de protocolo) - pero puede haber ahorro para cosas como int simplemente debido a la forma en que empaqueta ints ... (especialmente si tienden a estar en el lado menor [magnitud]). Finalmente, si T es en realidad objetos como Person , etc., debería ser un lot mejor que la serialización binaria, ya que es muy bueno para empacar objetos.

No sería algo trivial para los cuernos de zapato en matrices rectangulares, pero hazme saber si esto es algo que te gustaría probar.

* : no lo hace en este momento desde que " búferes de protocolo " La especificación no los admite, pero podemos hackear eso ...

La razón por la que deben existir tantos datos sobre los tipos es que su matriz de T podría ser de cualquier tipo, pero más específicamente, T podría ser del tipo SomeBaseClass, y aún podría almacenar SomeDerivedClass en esa matriz y el deserializador necesitaría saber esto.

Pero estos datos redundantes lo convierten en un buen candidato para la compresión, como han señalado otros.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top