Frage

Ich habe eine Klasse, die ich auf binäre serialize benötigen. Die Klasse enthält ein Feld wie folgt:

private T[,] m_data;

Diese mehrdimensionale Arrays kann ziemlich groß (Hunderttausende von Elementen) und einem primitiven Typs sein. Wenn ich Standard .net Serialisierung auf einem Objekt versucht, die Datei auf der Festplatte geschrieben war groß und ich denke, .net wird eine Menge von wiederholten Daten über Elementtypen zu speichern und möglicherweise nicht so effizient wie getan werden könnte.

Ich habe um für benutzerdefinierte Serializer gesucht, aber nicht alle, die mit multidimensionalen generischen Arrays beschäftigen gesehen. Ich habe auch mit einem in der .net-Komprimierung auf Byte-Array des Speicher-Streams folgenden Serialisierung mit einigem Erfolg experimentiert, aber nicht so schnell / komprimierte, wie ich gehofft hatte.

Meine Frage ist, sollte ich versuchen, eine benutzerdefinierte Serializer schreiben optimal dieses Array für den entsprechenden Typ serialisiert werden (dies scheint ein wenig entmutigend), oder sollte ich verwenden Standard .net Serialisierung und fügen Kompression?

Jede Beratung über den besten Ansatz würde die meisten geschätzt werden, oder Links zu Ressourcen zeigen, wie die Serialisierung eines mehrdimensionalen generischen Array in Angriff zu nehmen - wie erwähnt bestehende Beispiele ich gefunden habe, nicht über solche Strukturen unterstützen.

War es hilfreich?

Lösung

Hier ist, was ich kam mit. Der folgende Code macht einen int [1000] [10000] und schreibt sie über das BinaryFormatter zu 2-Dateien mit - eine mit Reißverschluss und einer nicht.

Die Zip-Datei ist 1,19 MB (1.255.339 Bytes) Entpackten ist 38,2 MB (40.150.034 Byte)

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

Ich kann nicht denken Sie an eine bessere / einfache Möglichkeit, dies zu tun. Die gezippte Version ist verdammt eng.

würde ich mit dem BinaryFormatter + GZipStream gehen. etwas Gewohnheit machen würde überhaupt nicht lustig.


[Bearbeiten von MG] Ich hoffe, dass Sie nicht von einem bearbeiten beleidigt sein, aber die Uniform wiederholt Range (0, Breite) ist, die Dinge in beträchtlichem Ausmaß Schrägstellung; Änderung:

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

Und versuchen Sie es; Sie temp_notZipped.txt bei 40MB, temp_zipped.txt bei 62MB sehen. Nicht so ansprechend ...

Andere Tipps

Die beste Codelänge / Ausgabegrößenverhältnis wäre Ihr Array BitConverter mit kodieren, um alle Elemente in ihrer kompakten binären Format zu konvertieren. Es ist Handbuch, ich weiß, aber 80-90% Platz im Vergleich zu .NET binärer Serialisierung speichern.

Können Sie „groß“ definieren? Das 1000x10000xint Beispiel (ein anderer post) kommt bei 40Mb out; und 1000x10000x4 Bytes (= int) ist 38MB. Als Gemeinkosten gehen, das ist nicht so schlimm.

Welche Art von Daten ist T wahrscheinlich zu sein? Nur primatives? Ich denke, dass ich wahrscheinlich protobuf-net rechteckige arrays* unterstützen bearbeiten könnte - aber eine Art von Draht-Kompatibilität halten wir wahrscheinlich einen Header benötigen würden (ein Byte) pro Element -. dh 9MB von Overhead für das 1000x10000 Beispiel

Dies ist wahrscheinlich nicht wert für Dinge wie float, double, etc. (da sie wörtlich unter „Protokoll-Puffer“ gespeichert werden) - aber es kann Einsparungen für Dinge wie int einfach sein durch, wie es packt Ints ... (vor allem, wenn sie auf der kleineren Seite zu neigen [Größe]). Schließlich, wenn T tatsächlich Objekte wie Person etc ist, dann sollte es ein Los besser als binäre Serialisierung, da es sehr gut an Objekte zu packen.

Es wäre nicht trivial sein, Schuh-Horn in rechteckigen Anordnungen, aber lassen Sie mich wissen, ob dies etwas, das Sie bei dem Versuch interessiert sein würde.

*: es funktioniert nicht in dem Moment, da die „Protokollpuffer“ spec nicht unterstützt werden, aber wir können um das hacken ...

Der Grund muss es so viele Daten über die Typen sein, ist, dass Ihr Array von T jede Art sein könnte, aber genauer gesagt, könnte T vom Typ Somebaseclass sein, und man konnte noch speichern SomeDerivedClass in diesem Array und der Deserializer müßte, dies wissen.

Aber diese redundanten Daten machen es einen guten Kandidaten für die Kompression, wie andere hier schon berichtet haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top