Das Kopieren des letzten Records ist natürlich eine ganz brauchbare Idee, aber falls es noch irgendwelche Index/Sortierinformationen geben sollte, entsteht ein u.U. ganz beträchtlicher Overhead.
Ich würde jedem Datensatz einen Header spendieren, 2 oder 4 Byte. Ist der Header = 0, dann ist der Record gültig. Wenn nicht, dann enthält der Header die Datensatznummer des nächsten gelöschten Records.
Der 1. Datensatz enthält keine Daten, dafür einen Verweis auf den ersten gelöschten Datensatz und vielleicht auch andere Informationen.
Sei Header [x] der Verweis auf den ersten gelöschten Datensatz des x.ten Datensatzes.
Um einen Datensatz x zu löschen, reicht es, sowas zu schreiben:
Quelltext
1: 2: 3:
| Prozedur DatensatzLoeschen (x : Datensatznummer) Header[x] <-- Header[1] Header[1] <-- x |
Man implementiert also eine einfache verkettete Liste. Anfangs ist Header[1] = -1
Wenn man einen Datensatz einfügt, steht ein freier DS ja in Header[1]. Also:
Quelltext
1: 2: 3: 4: 5: 6: 7:
| Funktion ReserviereNachsteFreieDatensatznummer liefert Datensatznummer; If Header[1] = -1 Then /* keine zuvor gelöschten Datensätze vorhanden */ Resultat <-- Höchste Datensatznummer + 2 /* Der 1.Datensatz ist ja reserviert */ SchreibeLeerenDatensatz (Resultat) /* Datensatz schreiben */ Else Resultat <-- Header[1] Header[1] <-- Header[Header[1]] |
Und wenn man die Datei wieder rekonstruieren muss, kann man mit der Marke im Header einfach die Spreu vom Weizen trennen.
Na denn, dann. Bis dann, denn.