una recorrer multidimensionales matriz matrices imprimir enteros dinamica cuadrada consola como cargar c# .net serialization binary

recorrer - matriz en c# consola



Optimización de la serialización binaria para matrices genéricas multidimensionales (4)

Tengo una clase que necesito serializar binariamente. La clase contiene un campo de la siguiente manera:

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.

He buscado serializadores personalizados pero no he visto ninguno que se ocupe de matrices genéricas multidimensionales. También experimenté con la compresión .NET incorporada en una matriz de bytes de la secuencia de memoria después de la serialización con cierto éxito, pero no tan rápido / comprimido como esperaba.

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

Cualquier consejo sobre el mejor enfoque sería muy apreciado, o enlaces a recursos que muestran cómo abordar la serialización de una matriz genérica multidimensional, como mencioné en los ejemplos existentes que he encontrado que no respaldan tales estructuras.


La mejor relación entre tamaño de código y tamaño de salida sería codificar su matriz mediante 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 1000x10000xint (otra publicación) sale a 40Mb; y 1000x10000x4 bytes (= int) es 38MB. Como los gastos generales van, eso no es terrible.

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

Esto probablemente no valga la pena para cosas como float , double , etc. (ya que se almacenan textualmente en "búferes de protocolo"), pero puede haber ahorros para cosas como int simplemente debido a la forma en que los empaqueta ... (especialmente si tienden a estar en el lado más pequeño [magnitud]). Finalmente, si T es realmente objetos como Person , etc., debería ser mucho mejor que la serialización binaria, ya que es muy bueno para empacar objetos.

No sería trivial tocar cuerno en arreglos rectangulares, pero avíseme si esto es algo que le interesaría probar.

* : no lo hace en este momento dado que la especificación "buffer de protocolo" no los admite, pero podemos hackear eso ...


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

El archivo comprimido es de 1,19 MB (1,255,339 bytes). La descompresión 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 comprimida es bastante apretada.

Me gustaría ir con BinaryFormatter + GZipStream. Hacer algo personalizado no sería divertido en absoluto.

[Editar por MG] Espero que no te ofenda por una edición, pero el rango repetido uniforme (0, ancho) está desviando 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 tan atractivo ...


La razón por la que debe haber 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 notado otros.