Dies tritt für mich als programmiersprachenunabhängiges Problem auf.
Ich habe eine Datei mit dem Inhalt
aaabddd
Wenn ich einfügen wollen C
hinter b
dann meinen Code Bedürfnisse neu zu schreiben ddd
zu bekommen
aaabCddd
Warum kann ich nicht einfach C
an dieser Stelle einfügen ?
Ich kann das nicht in Java, Python, .... Ich kann das nicht unter Linux, Windows, .... Habe ich recht?
Ich verstehe nicht, warum C
nicht einfach ohne die zusätzlichen Schreibvorgänge eingefügt werden kann. Würde jemand bitte erklären, warum das so ist?
Antworten:
Angesichts der Tatsache, dass die meisten Dateisysteme den Inhalt von Dateien in einzelnen Blöcken speichern, die nicht unbedingt auf der physischen Festplatte zusammenhängend sind, sondern über Zeigerstrukturen verknüpft sind, sollte ein solcher Modus - "Einfügen" statt "Anhängen" oder "Überschreiben" - verwendet werden möglich zu sein und sicherlich effizienter zu machen als das, was wir jetzt tun müssen: den gesamten Inhalt lesen, den Bytestrom bearbeiten und den gesamten Inhalt neu schreiben.
Ob gut oder schlecht, die UNIX-Semantik von Dateisystemen wurde in den 1970er Jahren nach dem "groben und einfachen" Paradigma entwickelt: Sie ermöglicht es Ihnen, alles zu tun, aber nicht unbedingt auf die effizienteste Art und Weise. Heutzutage ist es fast undenkbar, einen neuen Modus zum Öffnen von Dateien in die Ebene des virtuellen Dateisystems einzuführen, und hoffen, dass die wichtigsten Dateisysteme diese unterstützen. Dies ist ein kleiner Ärger von mir, aber leider ist es unwahrscheinlich, dass er bald behoben wird.
quelle
Theoretisch könnten Sie eine Datei implementieren, die dies zulässt. Für maximale Flexibilität müssen Sie jedoch zusammen mit jedem Byte in der Datei einen Zeiger auf das nächste Byte speichern. Unter der Annahme eines 64-Bit-Zeigers würde dies bedeuten, dass 8 von 9 Bytes Ihrer Datei aus internen Zeigern bestehen. Das Speichern von 1000 Byte tatsächlicher Daten würde also 9000 Byte Speicherplatz erfordern. Das Lesen der Datei wäre auch langsam, da Sie jedes Byte lesen, den Zeiger lesen, dem Zeiger folgen müssen, um das nächste Byte zu lesen usw., anstatt große, zusammenhängende Datenblöcke von der Festplatte zu lesen.
Offensichtlich ist diese Art von Ansatz nicht praktikabel. Sie können die Datei jedoch in 32-KB-Blöcke aufteilen. Dies würde es relativ einfach machen, 32 KB Daten an einer beliebigen 32 KB-Grenze in der Datei hinzuzufügen. Es würde es nicht einfacher machen, ein einzelnes Byte als 5. Byte der Datei hinzuzufügen. Wenn Sie jedoch in jedem Block freien Speicherplatz reservieren, können Sie kleine Datenzusätze zulassen, die sich nur auf die Daten in diesem einzelnen Block auswirken. Sie hätten natürlich eine Strafe in Bezug auf die Dateigröße, aber möglicherweise eine vernünftige. Das Herausfinden, wie viel Speicherplatz reserviert und wie Blöcke aufgeteilt werden müssen, ist für eine bestimmte Anwendung in der Regel viel einfacher als für ein Allzwecksystem. Was in einem Kontext funktioniert, kann in einem anderen Kontext je nach Dateizugriff und sehr schlecht sein Modifikationseigenschaften.
Tatsächlich implementieren viele Systeme, die viel Zeit mit der Interaktion mit Dateien verbringen, etwas wie das, was ich oben beschrieben habe, wenn sie ihre bestimmte Dateiabstraktion implementieren. Beispielsweise implementieren Datenbanken im Allgemeinen ein Konzept eines "Blocks" als kleinste E / A-Einheit, mit der sie arbeiten können, und reservieren im Allgemeinen etwas Speicherplatz für zukünftiges Wachstum, sodass die Aktualisierung einer Zeile in einer Tabelle nur die Ein Block, in dem diese Daten gespeichert werden, anstatt die gesamte Datei neu zu schreiben. Unterschiedliche Datenbanken haben natürlich unterschiedliche Implementierungen mit unterschiedlichen Kompromissen.
quelle
Das "Problem" besteht darin, wie Dateien byteweise auf das Speichermedium geschrieben werden.
In der einfachsten Darstellung ist eine Datei nichts anderes als eine Reihe von Bytes, die auf die Festplatte (auch als Speichermedium bezeichnet) geschrieben werden. Ihre ursprüngliche Zeichenfolge sieht also so aus:
Und Sie möchten
C
an Position 0x04 einfügen . Dazu müssen die Bytes 4 - 6 um ein Byte nach unten verschoben werden, damit Sie den neuen Wert einfügen können. Wenn Sie dies nicht tun, überschreiben Sie den Wert, der derzeit bei 0x04 liegt und nicht Ihren Wünschen entspricht.Der Grund, warum Sie das Ende der Datei nach dem Einfügen eines neuen Werts neu schreiben müssen, liegt darin, dass in der Datei kein Platz vorhanden ist, um den eingefügten Wert zu akzeptieren. Andernfalls würden Sie überschreiben, was dort war.
Anhang 1 : Wenn Sie den Wert von durch ersetzen möchten, müssen Sie den Schwanz der Zeichenfolge nicht neu schreiben. Das Ersetzen eines Werts durch einen Wert gleicher Größe erfordert kein Umschreiben.
b
C
Anhang 2 : Wenn Sie die Zeichenfolge
ab
durch ersetzen möchten, müssenC
Sie den Rest der Datei neu schreiben, da Sie eine Lücke in der Datei erstellt haben.Nachtrag 3 : Block Level - Konstrukte wurden erstellt , um große Dateien zu erleichtern Handhabung zu behandeln. Anstatt zusammenhängenden Speicherplatz für Ihre Datei im Wert von 1 Million zu finden, müssen Sie jetzt nur noch verfügbare Blöcke im Wert von 1 Million finden, in die Sie schreiben können.
Theoretisch könnten Sie ein Dateisystem erstellen, das Byte für Byte verknüpft, ähnlich wie Blöcke. Dann können Sie ein neues Byte einfügen, indem Sie das auf | aktualisieren von Zeigern an der entsprechenden Stelle. Ich würde eine Vermutung wagen, dass die Leistung darauf ziemlich schlecht wäre.
Verwenden Sie, wie Großmeister B vorgeschlagen hat , ein Bild gestapelter Dominosteine, um visuell zu verstehen, wie die Datei dargestellt wird.
Sie können keinen weiteren Domino in die Domino-Linie einfügen, ohne dass alles umkippt. Sie müssen den Raum für das neue Domino schaffen, indem Sie die anderen entlang der Linie bewegen. Das Verschieben von Dominosteinen entlang der Linie entspricht dem erneuten Schreiben des Endes der Datei nach der Einfügemarke.
quelle
Das Einfügen in eine Datei ist in den meisten Dateisystemen nicht implementiert, da es als "teurer" Vorgang (zeit- und raumfressender Vorgang) mit potenziell langfristigen "teuren" Auswirkungen und zusätzlichen Fehlermodi angesehen wird.
Ein Dateisystem mit Einfügesemantik würde wahrscheinlich entweder Shift & Insert verwenden (möglicherweise sehr teuer, wenn Sie am Anfang einer großen Datei einfügen, aber keine / wenige langfristige Nebenwirkungen) oder eine Art verallgemeinerte Heap-Zuordnung mit Zuordnungsgrößen variabler Länge ( In einigen Fällen sehr schlecht benommen [Stellen Sie sich die Gesichter der interaktiven Benutzer vor, wenn sie versuchen, eine Datei während eines Stop-the-World-GC zu speichern!]).
Wenn Sie experimentieren möchten, können Sie einfach eine Datei-E / A-Abstraktion in Java oder Python erstellen, die das Einfügen implementiert. Wenn Sie erfolgreich sind und sich gut verhaltene Leistungsmerkmale aufweisen, haben Sie die Grundlage für ein hervorragendes Forschungspapier. Viel Glück.
quelle
Der effizienteste Weg, einen Byteblock in die Mitte einer Datei einzufügen, wäre:
quelle
Zuerst müssen Sie alles nach dem Einfügepunkt lesen und dann um so viel Platz zurückschreiben, wie Sie einfügen möchten. Dann können Sie Ihre "Einfügen" -Daten an die richtige Stelle schreiben. Extrem schlechter Leistungsbetrieb, daher nicht nativ unterstützt.
quelle
Wenn Sie direkten Zugriff auf eine Datei haben, verwenden Sie eine niedrige Ebene, mit der komplexere Strukturen erstellt werden können. Erwägen Sie, eine Datenbank mit Ihren Daten zu erstellen, die die von Ihnen benötigten Zugriffstypen einschließlich des Einfügens ermöglicht.
Es wäre kostengünstiger, wenn Sie nur die Datei durchlaufen müssen und keine zufälligen Zugriffe auf einen bestimmten Offset ausführen müssen. Wenn Sie einen zufälligen Zugriff durch Versatz in der Datei benötigen, müssen Sie den Index für alle Bytes jenseits der Einfügemarke aktualisieren.
Im Allgemeinen zahlen Sie für die Indizierung von Datenstrukturen, den Speicher zum Speichern des Index und zusätzliche Festplattenzugriffe zum Aktualisieren.
quelle