wie performat teil aus grosser binärdatei löschen?
-
habe ein problem, das ich irgentwie nicht performat lösen kann. es geht darum, aus u.u. grossen dateien(>4gb) kleine teile(ca. 350byte) ab einem bestimmten offset zu löschen und den rest wieder zusammenzufügen. hab das bisher so gemacht, das ich den ersten teil der datei(bis zum offset des zu löschenden bereichs) in eine neu erstellte datei kopiert haben, dann den dateizeiger der quelldatei auf den bereich nach dem zu löschenden block gesetzt habe und dann einfach den rest in die neue datei kopiert habe. das geht dauert nur sehr lange. jetzt meine frage:
gibts da irgenteinen trick bzw. funktion mit der ich das ganze eleganter und vorallem schneller lösen kann?
-
Hast du schon mit setvbuf() und/oder setbuf() rumgespielt?
Kopierst du mit fread() oder fgetc() oder ... ?
-
Dateien werden ja einer Clusterkette folgend gelesen. Was, wenn du einfach die Adresse des nächsten Clusters änderst?^^
Edit: Na gut, das ist Unsinn. Schon wieder zu wenig nachgedacht.
-
ja, das mit der clusterkette hatte ich mir auch überlegt. aber da hat ein cluster halt viel mehr inhalt als den zu löschende teil und den rest müsste ich dann auch irgentwie ohne leerbytes bündig an den rest der kette hängen und quasi daten des nächsten clusters in den alten kopieren um den rest aufzufüllen. im endeffekt läuft es dann auf komplettes kopieren des restes raus. das wäre performat, wenn der zu löschende teil weit hinten liegt, aber nur dann. auserdem: gibt es wirklich c-funktionen, welche das manipulieren von dateisystem-clustern erlauben?
apropos setbuf: ich reserviere 50mb ram und kopiere das ganze in 50mb blöcken.
andererseits, wenn der kunde mit daten >4gb rumspielt, dann kann er nicht erwarten, daß das so schnel geht wie mit 4mb.
-
Kommt es in Frage, die betreffenden Teile einfach zu ändern, anstatt ganz auszuschneiden? Du könntest dort zum Beispiel Nullzeichen, Kommentarzeichen, NOP-Codes oder ähnliches, je nach Format, einfügen.
Das obige wäre die Tricklösung.
Falls der Trick nicht funktioniert, ist deine Vorgehensweise wohl schon das beste was geht (wobei man auch da natürlich geschickt oder ungeschickt vorgehen kann, siehe DirkB). Der Umgang mit so großen Dateien ist nun einmal naturgemäß etwas langsam.
Eine systemspezifische Lösung die mir noch einfällt: Unter POSIX gibt es ftruncate. Falls der Block den du löschen möchtest eher am Ende der Datei ist, shufflest du alles was danach kommt um die Blocklänge nach vorne und schneidest dann das Ende ab. Falls der Block sehr weit vorne ist, kommt das natürlich auf einen ähnlichen Kopieraufwand hinaus wie deine jetzige Lösung. Aber je weiter hinten, desto besser.
Diese Lösung hat den Vorteil und Nachteil, die Datei in-place zu verändern. Das heißt als Vorteil, du legst keine Kopie an und sparst dadurch jede Menge Platz während der Aktion. Das heißt als Nachteil, du legst keine Kopie an und wenn bei der Aktion etwas schiefgeht (Programm wird zwischendurch unterbrochen), dann hast du kein Backup und die Daten sind zerhackstückelt.
-
ja, ich könnte schon den zu löschenden teil einfach da lassen und in der registrierung als "nicht belegt" kennzeichnen und dann wenn ich wieder einen neuen teil einfügen will, ihn an dieser stelle einfügen anstatt hinten(alle teile sind gleichgross -es sind bildsignaturen). das hatte ich auch schon überlegt, allerdings hab ich dann immer eine datei, welche das maximum an grösse aufweist, die irgentwann zu einem peak-zeitpunkt mal nötig war und in zeiten wo ich dann nur ca. 10% aller daten benötige hat die datei trotzdem 100% grösse. ich glaube ich lass es einfach so, so lange dauert es jetzt auch nicht. ich wollte halt nur sichergehen, das ich nicht irgenteine systemfunktion übersehen habe, welche genau dieses problem handeln kann. aber offenbar gibts die nicht, dann bin ich beruigt nicht kompletten müll programmiert zu haben.