Leider können Sie Zeilen am Anfang einer Datei nicht abschneiden / überschreiben, ohne das gesamte Ding neu zu schreiben.
Ich habe gerade an einen neuen Ansatz gedacht, der Ihnen vielleicht helfen könnte ...
Sie könnten Ihrer Datei einen kleinen Header hinzufügen, der die folgende Struktur hat:
Bearbeiten: Quatsch, ich habe gerade eine Variante eines Umlaufspeichers beschrieben!
Kopfzeilenfelder
Bytes 00 - 07 (long)
- Gesamtzahl (aktuelle) Anzahl der in die Datei geschriebenen Zeilen. Bytes 08 - 15 (long)
- Zeiger auf den Anfang der "tatsächlichen" ersten Zeile Ihrer Datei. Dies ist zunächst das Byte nach dem Ende des Headers, wird aber später geändert, wenn Daten überschrieben werden. 'Bytes 16 - 23 (long)
- Länge des "Endabschnitts" der Datei. Auch dies wird zunächst Null sein, wird sich aber später ändern, wenn Daten überschrieben werden. Lesealgorithmus (Pseudocode)
Liest die gesamte Datei.
%Vor%Schreibalgorithmus (Pseudocode)
Schreibt eine beliebige Anzahl neuer Zeilen in die Datei.
%Vor%Nicht ein schrecklich einfacher Algorithmus, ich gebe es zu! Trotzdem denke ich, dass es in gewisser Weise ziemlich elegant ist. Lassen Sie mich wissen, wenn das nicht klar ist. Hoffentlich sollte es genau das tun, was Sie jetzt wollen.
Nun, wenn Ihre Zeilen garantiert eine konstante Länge (in Bytes) haben, könnten Sie einfach genug zurück zum entsprechenden Punkt suchen und existierende Daten überschreiben. Dies scheint jedoch eine eher unwahrscheinliche Situation zu sein. Wenn es Ihnen nichts ausmacht, die Beschränkung aufzuerlegen, dass Ihre Zeilen eine maximale Länge haben müssen, und zusätzlich jede der Zeilen, die Sie schreiben, auf diese maximale Länge aufzufüllen, dann könnte das die Sache für Sie leicht machen. Dennoch hat es seine Nachteile, wie zum Beispiel eine stark erhöhte Dateigröße unter bestimmten Umständen (d. H. Die meisten Zeilen sind viel kürzer als die maximale Länge). Es hängt alles von der Situation ab, ob dies akzeptabel ist oder nicht ...
Schließlich möchten Sie vielleicht stattdessen ein vorhandenes Protokollierungssystem verwenden, abhängig von Ihrem genauen Zweck.
Die übliche Methode zur Protokollierung, die nicht in der Größe explodiert, ist die Verwendung von Rolling-Log-Dateien, die einmal täglich oder ähnlich wiederholt werden und nur die letzten N Dateien enthalten.
Zum Beispiel erstellen Sie jeden Tag eine neue Logdatei mit dem Dateinamen 'application_2009_05_20.log' und beginnen mit dem Schreiben, immer anhängend.
Sobald Sie 14 Tage lang Logdateien haben, löschen Sie die ältesten.
Da Dateien Byte-orientiert sind und Sie einen zeilenorientierten Dienst benötigen, haben Sie zwei Möglichkeiten:
implementiert einen zeilenorientierten Wrapper um die Datei
wechseln Sie zu einem zeilenorientierten Gerät. Nur von ganzem Herzen: SQLite hat einige nette C ++ - Wrapper zur Verfügung.
Verwenden Sie einen Ringpuffer und schreiben Sie den Puffer in eine Datei für jedes Add.
Hier ist eine kleine und einfache Codegröße Lösung. Es ist ein einfacher Ringspeicher für Strings und jedes Mal, wenn Sie Strings hinzufügen, schreibt er den gesamten String-Puffer in die Datei (natürlich entstehen Ihnen signifikante Kosten für das Schreiben all Strings für einen einzelnen Add-Vorgang, das ist nur für eine kleine Anzahl von Strings geeignet).
Einfache Implementierung des Ringspeichers mit Ausgabe in eine Datei:
%Vor%Also hatten wir im obigen Beispiel 5 Zeilen Eingabe und unser Puffer war nur 4 Zeilen lang. Daher sollte die Ausgabe nur 4 Zeilen haben und die erste Zeile sollte durch die letzte Zeile "Goodbye world" überschrieben werden. Sicher genug, die erste Zeile der Ausgabe bestätigt "Goodbye World":
%Vor%Einfache Lösung:
Diese Lösung bietet eine konstante Dateilänge anstelle einer konstanten Anzahl von Zeilen innerhalb der Datei. Die Anzahl der Linien variiert mit der Zeit abhängig von der Länge. Diese Lösung erschwert das schnelle Suchen nach bestimmten Zeilennummern. Sie können jedoch einige Indikatordaten oben oder unten an der Datei anheften, um dies zu vereinfachen.
"Clever" Lösung (Variation der obigen Lösung):
Verwenden Sie einfach den gleichen Trick, der manchmal für Deques verwendet wird. Gehen Sie einfach vom Anfang der Datei bis zum Ende, aber verfolgen Sie, wo der Anfang / das Ende der Datei ist. Sie könnten ein Unwrap-Dienstprogramm schreiben, um diese Datei in eine Standarddatei umzuwandeln, wenn Sie sie mit einem Programm lesen wollten, das sie nicht unterstützt. Diese Lösung ist wirklich einfach zu implementieren, aber ich mag die obige Version besser.
Hässliche Lösung:
Fügen Sie beim Hinzufügen von Zeilen eine moderate Menge an Auffüllung zu jeder hinzugefügten Zeile hinzu.
Jedes Mal, wenn Sie eine neue Zeile hinzufügen möchten, gehen Sie wie folgt vor:
Beachten Sie, dass dies ziemlich schlecht funktioniert, es sei denn, Ihre Zeilen sind hinsichtlich der Länge ziemlich konsistent. Eine einfachere Lösung besteht darin, zu garantieren, dass Zeilen von konstanter Länge sind (aber in irgendeiner Weise dazu verwendet werden, mehrzeilige "Zeilen" zu erzeugen, falls Sie diese Länge überschreiten.
Wenn die Dateien Textdateien sein müssen:
Dies ist bei unterschiedlichen Leitungslängen sehr problematisch. Ihre ersten zwei Zeilen sind jeweils 80 Zeichen, wie überschreiben Sie das mit einer Zeile mit 100 Zeichen?
Wenn die neue Zeile die erste Zeile ersetzen soll, würde dies zu einer Dateieinfügung führen, was eine sehr teure Operation ist (im Grunde muss der gesamte Rest der Datei gelesen und geschrieben werden) . Das wollen Sie wirklich nicht für alle, sondern nur für minimale Datenmengen tun.
Wenn dies für den Protokollierungszweck ist, verwenden Sie rollng-Protokolldateien - z. einen Tag (wie von Lassevek vorgeschlagen). Ich habe es noch einfacher gemacht: Wenn die Dateigröße ein Limit überschreitet, wird die alte Datei in .bak umbenannt (alte .bak wird gelöscht) und neu gestartet. Mit einer Grenze von 1 MB erhält dies z.B. die letzten 1 MB, während nie mehr als 2 MB belegen.
Sie könnten einen ähnlichen Mechanismus mit zwei oder mehr Dateien verwenden. Verschieben Sie den "Rollover" grundsätzlich in Dateien und nicht in Zeilen.
Wenn die Datei ein proprietäres Format hat:
Verwenden Sie eine einfache DB-Engine (wie SQLite wie vorgeschlagen) oder einen anderen strukturierten Speichermechanismus.
Sie könnten log4cxx
mit einem RollingFileAppender
, um diese Informationen in eine Protokolldatei zu schreiben. Der RollingFileAppender
behandelt das Überrollen der Protokolldatei, wenn sie eine bestimmte Größe erreicht. Ich denke nicht, dass es genau ist, was du willst, aber es ist ziemlich einfach - vielleicht wird es das tun.
Erstellen Sie einfach ein Mapping der Datei der benötigten Größe (CreateFileMapping oder mmap), schreiben Sie die Zeilen in den Puffer und beginnen Sie von vorne, wenn die maximale Anzahl erreicht ist.
Ich habe das gesehen, indem ich die aktuelle Schreibposition für die Datei irgendwo behalte. Wenn Sie eine Zeile hinzufügen müssen, suchen Sie nach der Position, schreiben die Zeile und aktualisieren die Position atomar. Wenn Sie überlaufen, suchen Sie vor dem Schreiben der Zeile eine Null. Wir tun dies heute für größenbeschränkte zirkuläre Protokolldateien. Es ist etwas seltsam, es auf einer Linie-beschränkten Basis zu tun, aber könnte wahrscheinlich in einer ähnlichen Weise getan werden. Unsere Schreibschleife sieht ungefähr so aus:
%Vor% Der schwierige Teil besteht darin, die aktuelle Schreibposition beizubehalten und eine Möglichkeit zu finden, das Lesen der Datei zu koordinieren (z. B. mit dem Dienstprogramm tail
), während Ihre Anwendung darauf schreibt. Ihr Leser-Dienstprogramm muss auch die Schreibposition verfolgen, so dass die Leseschleife zu:
Dies ist nicht in einer bestimmten Sprache - es ist nur Pseudocode, aber die Idee ist da. Natürlich habe ich die Bearbeitung aller interessanten Randfälle dem Leser überlassen.
Mit all dem gesagt ... stimme ich den anderen Meinungen zu. Tun Sie das nicht, es sei denn, Sie haben einen wirklich guten Grund. Es klingt wie eine großartige Idee, aber:
grep
, tail
, perl
usw. Insgesamt ist es besser, ein vorhandenes Paketprotokollierungspaket zu verwenden, das eine konfigurierbare Protokolldateiverwaltung ermöglicht. Schauen Sie sich Apache log4cxx oder Poco's Poco::Logger
.
Um das Ding mit variabler Größe zu umgehen, werden Sie wahrscheinlich ein Indirektionsschema und ein Zuweisungsschema erhalten. Dies würde aus einem indirekten Block mit einer festen Anzahl von "Zeigern" in der Datei und einem "nächsten zu schreibenden" Zeiger bestehen, der um N herumgehen würde.
Aber der Haupttrick wäre das Hinzufügen der Indirektion.