Lesen / Schreiben in eine große Datei in Java

8

Ich habe eine Binärdatei mit folgendem Format:

%Vor%

Wie Sie sehen, habe ich Platten mit unterschiedlichen Längen. In jedem Datensatz habe ich N Bytes, die enthält und ID und die Länge der Daten in Datensatz .

Diese Datei ist sehr groß und kann 3 Millionen Datensätze enthalten.

Ich möchte diese Datei nach einer Anwendung öffnen und den Benutzer die Datensätze durchsuchen und bearbeiten lassen. (Einfügen / Aktualisieren / Löschen von Datensätzen)

Mein ursprünglicher Plan besteht darin, eine Datei aus der Originaldatei zu erstellen und zu indizieren und für jeden Datensatz die nächste und die vorherige Datensatzadresse beizubehalten, um leicht vorwärts und rückwärts zu navigieren. (irgendeine Art von verknüpfter Liste, aber in einer Datei, die nicht im Speicher ist)

  • Gibt es eine Bibliothek (Java-Bibliothek), die mir hilft, diese Anforderung zu implementieren?

  • jede Empfehlung oder Erfahrung, die Sie für nützlich halten?

----------------- EDIT ----------------------------- -----------------

Danke für Anleitungen und Vorschläge,

weitere Informationen:

Die Originaldatei und ihr Format liegen außerhalb meiner Kontrolle (es ist eine Datei von Drittanbietern) und ich kann das Dateiformat nicht ändern. aber ich muss es lesen, Benutzer über Datensätze navigieren und einige von ihnen bearbeiten (neuen Datensatz einfügen / einen vorhandenen Datensatz aktualisieren / einen Datensatz löschen) und am Ende es wieder in das ursprüngliche Dateiformat speichern .

empfehlen Sie DataBase anstelle einer normalen Indexdatei?

----------------- SECOND EDIT ---------------------------- ------------------

Datensatzgröße im Update-Modus ist behoben. Das bedeutet, dass der aktualisierte (bearbeitete) Datensatz dieselbe Länge wie der ursprüngliche Datensatz hat, es sei denn, der Benutzer löscht den Datensatz und erstellt einen anderen Datensatz mit einem anderen Format.

Vielen Dank

    
mhshams 01.04.2011, 11:13
quelle

6 Antworten

2

Im Ernst, Sie sollten dafür KEINE Binärdatei verwenden. Sie sollten eine Datenbank verwenden.

Die Probleme mit dem Versuch, dies als eine normale Datei zu implementieren, rühren von der Tatsache her, dass Betriebssysteme es nicht erlauben, zusätzliche Bytes in die Mitte einer existierenden Datei einzufügen. Wenn Sie also einen Datensatz (an einer beliebigen Stelle außer dem Ende) einfügen, einen Datensatz aktualisieren (mit einer anderen Größe) oder einen Datensatz entfernen müssen, müssen Sie:

  • schreibt andere Datensätze (nach dem Einfüge- / Aktualisierungs- / Löschpunkt) neu, um Speicherplatz freizugeben oder zurückzugewinnen, oder
  • implementieren Sie eine Art von Speicherplatzverwaltung innerhalb der Datei.

All dies ist kompliziert und / oder teuer.

Glücklicherweise gibt es eine Klasse von Software, die solche Dinge implementiert. Es heißt Datenbanksoftware. Es gibt eine breite Palette von Optionen, von der Verwendung eines vollständigen RDBMS bis hin zu leichten Lösungen wie BerkeleyDB-Dateien.

Als Antwort auf Ihre erste und zweite Bearbeitung wird eine Datenbank immer noch einfacher.

Hier ist jedoch eine Alternative, die könnte besser für diesen Anwendungsfall als die Verwendung einer DB ... ohne komplizierte Freiraum-Verwaltung durchführen.

  1. Lesen Sie die Datei und erstellen Sie einen speicherinternen -Index, der IDs zu Dateipositionen zuordnet.

  2. Erstellen Sie eine zweite Datei für neue und aktualisierte Datensätze.

  3. Führen Sie den Datensatz hinzufügt / Updates / löscht:

    1. Eine Addition wird durch Schreiben des neuen Datensatzes an das Ende der zweiten Datei und Hinzufügen eines Indexeintrags dafür erledigt.

    2. Eine Aktualisierung wird durch Schreiben des aktualisierten Datensatzes an das Ende der zweiten Datei und Ändern des vorhandenen Indexeintrags, um auf diesen zu verweisen, abgewickelt.

    3. Ein Löschvorgang wird ausgeführt, indem der Indexeintrag für den Schlüssel des Datensatzes gelöscht wird.

  4. Komprimieren Sie die Datei wie folgt:

    1. Erstellen Sie eine neue Datei.

    2. Lesen Sie jeden Datensatz in der alten Datei der Reihe nach und überprüfen Sie den Index auf den Schlüssel des Datensatzes. Wenn der Eintrag immer noch auf den Speicherort des Datensatzes zeigt, kopieren Sie den Datensatz in die neue Datei. Sonst überspringen Sie es.

    3. Wiederholen Sie Schritt 4.2 für die zweite Datei.

  5. Wenn Sie alle oben genannten Schritte erfolgreich ausgeführt haben, löschen Sie die alte und die zweite Datei.

Beachten Sie, dass Sie den Index im Speicher behalten müssen. Wenn das nicht machbar ist, wird die Implementierung komplizierter ... und mehr wie eine Datenbank.

    
Stephen C 01.04.2011, 11:23
quelle
2

Eine Datendatei und eine Indexdatei wären die allgemeine Grundidee für eine solche Implementierung, aber bei wiederholten Datenaktualisierungen / -löschungen usw. würden Sie sich mit Datenfragmentierung beschäftigen. Diese Art von Projekt an sich , sollte ein separates Projekt sein und sollte nicht Teil Ihrer Hauptanwendung sein. Im Wesentlichen ist jedoch eine Datenbank erforderlich, da sie speziell für solche Operationen und Anwendungsfälle entwickelt wurde. Sie können damit auch Ihre Datenstruktur suchen, sortieren und erweitern (ändern), ohne eine interne (benutzerdefinierte) Umgestaltung vornehmen zu müssen. Lösung.

Darf ich vorschlagen, dass Sie Apache Derby herunterladen und eine lokale eingebettete Datenbank erstellen ( Derby tut es für Sie wollen Sie eine neue eingebettete Verbindung zur Laufzeit erstellen). Es ist nicht nur schneller als alles, was Sie selbst schreiben, sondern erleichtert auch die Wartung Ihrer Anwendung.

Apache Derby ist eine einzelne JAR-Datei, die Sie einfach mit Ihrem Projekt einbinden und verteilen können (siehe Lizenz wenn in Ihrer App ein rechtliches Problem auftritt. Es besteht keine Notwendigkeit für einen Datenbankserver oder Software von Drittanbietern; Es ist alles reines Java.

Unter dem Strich hängt alles davon ab, wie groß Ihre Anwendung ist, wenn Sie die Daten über viele Clients hinweg teilen müssen, wenn die Geschwindigkeit ein kritischer Aspekt Ihrer App ist, usw.

Für ein eigenständiges Einzelbenutzerprojekt empfehle ich Apache Derby. Für eine n-Tier -Anwendung sollten Sie sich die MySQL , PostgreSQL oder ( hrm ) sogar Oracle . Die Verwendung bereits entwickelter und getesteter Lösungen ist nicht nur schlau, sondern reduziert auch Ihre Entwicklungszeit (und Wartungsaufwand).

Prost.

    
Yanick Rochon 01.04.2011 11:30
quelle
1

Im Allgemeinen ist es besser, eine Bibliothek oder Datenbank die Arbeit für Sie erledigen zu lassen.

Sie möchten möglicherweise keine SQL-Datenbank haben und es gibt viele einfache Datenbanken, die kein SQL verwenden. Ссылка listet 122 davon auf.

Wenn Sie dies schreiben, sollten Sie zumindest die Quelle für eine dieser Datenbanken lesen, um zu sehen, wie sie funktionieren.

Abhängig von der Größe der Aufzeichnungen sind 3 Millionen nicht so viel und ich würde vorschlagen, dass Sie so viel Speicher wie möglich behalten.

Das Problem, das Sie wahrscheinlich haben, ist sicherzustellen, dass die Daten konsistent sind und die Daten wiederhergestellt werden, wenn eine Beschädigung auftritt. Das zweite Problem besteht darin, effizient mit der Fragmentierung umzugehen (etwas, mit dem sich die hellsten Köpfe im GC befassen). Das dritte Problem besteht wahrscheinlich darin, den Index in einer Transaktionsweise mit den Quelldaten zu pflegen, um sicherzustellen, dass es keine Inkonsistenzen gibt.

Obwohl dies auf den ersten Blick einfach erscheinen mag, gibt es erhebliche Schwierigkeiten bei der Gewährleistung, dass Daten zuverlässig, wartbar und effizient zugänglich sind. Aus diesem Grund verwenden die meisten Entwickler eine vorhandene Datenbank / Datenspeicherbibliothek und konzentrieren sich auf die Funktionen, die für ihre Anwendung nicht erforderlich sind.

    
Peter Lawrey 01.04.2011 11:21
quelle
0

(Anmerkung: Meine Antwort bezieht sich auf das Problem im Allgemeinen, ohne Berücksichtigung von Java-Bibliotheken oder - wie die anderen Antworten auch - mit einer Datenbank (Bibliothek), die besser ist, als das Rad neu zu erfinden)

Die Idee, einen Index zu erstellen, ist gut und wird in Bezug auf die Leistung sehr hilfreich sein (obwohl Sie eine "Indexdatei" geschrieben haben, denke ich, dass sie im Speicher gehalten werden sollte). Das Generieren des Indexes sollte ziemlich schnell sein, wenn Sie die ID und die Aufzeichnungslänge für jeden Eintrag lesen und dann die Daten mit einer Dateisuche einfach überspringen.

Sie sollten auch über die Bearbeitungsfunktionalität nachdenken. Insbesondere das Einfügen und Löschen kann bei einer so großen Datei sehr langsam sein, wenn Sie es falsch machen (z. B. Löschen und dann Verschieben aller folgenden Einträge, um die Lücke zu schließen).

Die beste Option wäre, gelöschte Einträge nur als gelöscht zu markieren. Beim Einfügen können Sie eine davon überschreiben oder an das Ende der Datei anhängen.

    
schnaader 01.04.2011 11:26
quelle
0
  

Einfügen / Aktualisieren / Löschen von Datensätzen

Das Einfügen (und nicht nur das Anhängen) und das Löschen von Datensätzen in eine Datei ist teuer, da Sie den gesamten folgenden Inhalt der Datei verschieben müssen, um Platz für den neuen Datensatz zu schaffen oder den verwendeten Speicherplatz zu entfernen. Das Aktualisieren ist ähnlich teuer, wenn das Update die Länge des Datensatzes ändert (Sie sagen, dass sie eine variable Länge haben).

Das von Ihnen vorgeschlagene Dateiformat ist für die Art von Operationen, die Sie ausführen möchten, grundsätzlich ungeeignet. Andere haben vorgeschlagen, eine Datenbank zu verwenden. Wenn Sie nicht so weit gehen möchten, ist das Hinzufügen einer Indexdatei (wie Sie es vorschlagen) der richtige Weg. Ich empfehle, die Index-Datensätze alle gleich lang zu machen.

    
Raedwald 01.04.2011 11:55
quelle
0

Wie andere angegeben haben, scheint eine Datenbank eine bessere Lösung zu sein. Die folgenden Java-SQL-DBs könnten verwendet werden: H2 , Derby oder HSQLDB

Wenn Sie eine Indexdatei verwenden möchten, schauen Sie sich Berkley DB oder No Sql

Wenn es Gründe für die Verwendung einer Datei gibt, sehen Sie sich JRecord an. Es hat

  1. Mehrere Klassen zum Lesen / Schreiben von Dateien mit binären Datensätzen variabler Länge (sie wurden für Cobol VB-Dateien geschrieben). Jede Mainframe / Fujitsu / Open Cobol VB-Dateistruktur sollte die Aufgabe übernehmen.
  2. Ein Editor zum Bearbeiten von JRecord Dateien. Die neueste Version des Editors kann große Dateien verarbeiten (es verwendet Komprimierungs- / Übergabedateien). Der Editor muss die gesamte Datei herunterladen und nur ein Benutzer kann die Datei gleichzeitig bearbeiten.

Die JRecord-Lösung funktioniert nur, wenn

  • Es gibt eine begrenzte Anzahl (vorzugsweise einen) Benutzer, die sich alle an dem einen Ort befinden
  • Schnelle Infostruktur
Bruce Martin 02.04.2011 07:18
quelle

Tags und Links