Aus verschiedenen Gründen habe ich eine benutzerdefinierte Serialisierung, wo ich einige ziemlich einfache Objekte in eine Datendatei dumpen bin. Es gibt vielleicht 5-10 Klassen, und die Objektgraphen, die sich daraus ergeben, sind azyklisch und ziemlich einfach (jedes serialisierte Objekt hat 1 oder 2 Verweise auf ein anderes, das serialisiert wird). Zum Beispiel:
class Foo
{
final private long id;
public Foo(long id, /* other stuff */) { ... }
}
class Bar
{
final private long id;
final private Foo foo;
public Bar(long id, Foo foo, /* other stuff */) { ... }
}
class Baz
{
final private long id;
final private List<Bar> barList;
public Baz(long id, List<Bar> barList, /* other stuff */) { ... }
}
Das id-Feld ist nur für die Serialisierung, so dass ich beim Serialisieren in eine Datei Objekte schreiben kann, indem ich aufzeichne, welche IDs bisher serialisiert wurden, dann für jedes Objekt überprüfe, ob seine untergeordneten Objekte serialisiert wurden, und diejenigen schreibe, die nicht serialisiert wurden, und schließlich das Objekt selbst schreibe, indem ich seine Datenfelder und die IDs, die seinen untergeordneten Objekten entsprechen, schreibe.
Was mir Rätsel aufgibt, ist die Zuweisung von IDs. Ich habe darüber nachgedacht, und es scheint, dass es drei Fälle für die Zuweisung einer ID gibt:
- dynamisch erstellte Objekte -- id wird von einem Zähler zugewiesen, der inkrementiert
- Lesen von Objekten von der Festplatte -- id wird anhand der in der Datei gespeicherten Nummer zugewiesen
- Singleton-Objekte - Das Objekt wird vor jedem dynamisch erstellten Objekt erstellt, um ein Singleton-Objekt darzustellen, das immer vorhanden ist.
Wie kann ich diese richtig behandeln? Ich habe das Gefühl, dass ich das Rad neu erfinden muss, und es muss doch eine bewährte Technik für alle Fälle geben.
Klärung: Nur zur Information: Das Dateiformat, das ich im Auge habe, ist ungefähr das folgende (wobei ich ein paar Details auslasse, die nicht relevant sein sollten). Es ist optimiert, um eine ziemlich große Menge an dichten Binärdaten (zehn/hunderte von MB) zu verarbeiten, mit der Möglichkeit, strukturierte Daten darin einzuschleusen. Die dichten Binärdaten machen 99,9 % der Dateigröße aus.
Die Datei besteht aus einer Reihe von fehlerbereinigten Blöcken, die als Container dienen. Jeder Block kann als ein Byte-Array betrachtet werden, das aus einer Reihe von Paketen besteht. Es ist möglich, die Pakete nacheinander zu lesen (z. B. kann man feststellen, wo das Ende eines jeden Pakets ist, und das nächste beginnt unmittelbar danach).
Man kann sich die Datei also als eine Reihe von Paketen vorstellen, die über einer Fehlerkorrekturschicht gespeichert werden. Die überwiegende Mehrheit dieser Pakete sind undurchsichtige Binärdaten, die nichts mit dieser Frage zu tun haben. Eine kleine Minderheit dieser Pakete sind jedoch Elemente, die serialisierte strukturierte Daten enthalten und eine Art "Archipel" aus Daten-"Inseln" bilden, die durch Objektreferenzbeziehungen verbunden sein können.
Ich könnte also eine Datei haben, in der Paket 2971 ein serialisiertes Foo enthält, und Paket 12083 enthält ein serialisiertes Bar, das sich auf das Foo in Paket 2971 bezieht. (wobei die Pakete 0-2970 und 2972-12082 undurchsichtige Datenpakete sind)
Alle diese Pakete sind unveränderlich (und bilden daher aufgrund der Beschränkungen der Java-Objektkonstruktion einen azyklischen Objektgraphen), so dass ich mich nicht mit Problemen der Veränderbarkeit befassen muss. Sie sind außerdem Nachkommen eines gemeinsamen Item
Schnittstelle. Was ich tun möchte, ist, eine beliebige Item
Objekt in der Datei. Wenn die Item
enthält Verweise auf andere Item
s, die sich bereits in der Datei befinden, muss ich diese auch in die Datei schreiben, aber nur, wenn sie noch nicht geschrieben wurden. Andernfalls habe ich Duplikate, die ich irgendwie zusammenführen muss, wenn ich sie zurücklese.
0 Stimmen
Müssen Sie sich Gedanken über den Fall machen, dass Sie einige Objekte erstellt haben und dann einige von der Festplatte laden (mit IDs, die möglicherweise mit bereits vorhandenen Objekten in Konflikt geraten könnten)?
0 Stimmen
Ja, und ich denke, der Ansatz besteht darin, die IDs als zwei getrennte "Namensräume" zu behandeln und die bereits vorhandenen IDs den neuen zuzuordnen.
0 Stimmen
Müssen die Objekte in getrennten Paketen geliefert werden? Können sie alle in ein großes Paket gepackt werden? Werden die Objektpakete von den undurchsichtigen Binärdaten referenziert? Ich habe den Verdacht, dass die logischen Beziehungen mit dem physischen Speicher verwechselt werden.
0 Stimmen
Werden die Objektpakete von den undurchsichtigen Binärdaten referenziert: indirekt ja (d.h. sie werden unter Verwendung der Objektpakete interpretiert). Das und die Tatsache, dass ich diese Pakete ziemlich schnell in eine Datei streame und sie so schnell wie möglich geschrieben bekommen möchte, machen es ziemlich wichtig, sie bald nach ihrer Erzeugung in eine Datei zu schreiben. Ich könnte damit spielen, sie im Speicher zu halten und mich mit einem Aufräumprozess zu beschäftigen, der den Fall behandelt, dass der Paketgenerator auf halbem Weg durch das Schreiben von Paketen auf die Festplatte unterbrochen wird. Hier wird es komplizierter....
0 Stimmen
(und ich behandle dies als ein Strom und nicht eine Datei mit wahlfreiem Zugriff, nämlich ich will nicht zurück gehen und Teile der Datei später neu zu schreiben -- das würde Paket Bestellung von der Reihenfolge entkoppeln es in eine Datei geschrieben wird, aber auf Kosten der Komplexität)
0 Stimmen
Lassen Sie mich das noch einmal überprüfen: Die Binärdaten beziehen sich auf die Objekte. Sie könnten also ein Objektpaket haben, und die nachfolgenden Binärdatenpakete werden dann unter Verwendung des Objekts als Kontext interpretiert?
0 Stimmen
Ja... nun, binäre Datenpakete werden anhand der bisher erschienenen Objekte als Kontext interpretiert. (die Objekte kann man sich als "Ereignisse" vorstellen, die kleine unveränderliche Objekte sind, die Änderungen an einem veränderlichen Kontext darstellen)