Daten in Datei einfuegen
moin Ist es moeglich in Dateien Daten an beliebiger Stelle einzufuegen, ohne das die vorhandenen Daten ueberschrieben werden? Und das mit einer Methode, die auch noch plattformuebergreifend funktioniert? Im Modus 'r+' werden die vorhandenen Daten ueberschrieben: fd = open('test.txt', 'r+') fd.read() 'test1' fd.seek(0) fd.write('test2') fd.seek(0) fd.read() 'test2' Die Größe der zu schreibenden Daten ist bekannt, also koennte ich ja die Datei vorm schreiben mit 0-Bytes auffuellen. Aber wie mach ich das? Und im Modus 'a+' werden die Daten immer ans Ende der Datei angehaengt: fd = open('test.txt', 'a+') fd.read() 'test2' fd.seek(0) fd.write('test3') fd.seek(0) fd.read() 'test2test3' Das wuerde funktionieren, wenn ich die Datei vorm schreiben an der passenden Stelle teile und danach wieder zusammenfuege. Geht das ohne die Datei einzulesen (die Dateien koennen mehrere 100MB bis > 1GB gross sein)? thx & cu boesi PS: die Größe der einzufuegenden Daten ist immer 1MB, falls das wichtig sein koennte. -- Wenn de Lüch net waer un dr Neid #1671 : icq-intern gäbs lauter glückliche Leid #73628288 : icq-extern Uhne Lüch un Neid = ganz gewiß boesi111 : aim wär uf dr Ard is Paradies i171 : reallife _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
Alexander 'boesi' Bösecke wrote:
moin
Ist es moeglich in Dateien Daten an beliebiger Stelle einzufuegen, ohne das die vorhandenen Daten ueberschrieben werden? Und das mit einer Methode, die auch noch plattformuebergreifend funktioniert?
Nein. Oder soll das System die existierenden Daten auf der Platte rumschieben?
Die Größe der zu schreibenden Daten ist bekannt, also koennte ich ja die Datei vorm schreiben mit 0-Bytes auffuellen. Aber wie mach ich das?
Unter unix kannst du ein seek() über das Dateiende hinausmachen, wodurch automatisch alles bis zu deiner neuen Position mit \0 gefüllt wird. Das Dateisystem alloziert für Blocks (Grösse variiert), in die du nichts geschrieben hast, auch keinen Platz auf der Platte. Erst wenn du dort das erste mal tatsächlich etwas hinschreibst (und seien es lauter explizite \0), wird physikalisch Raum beansprucht. Unter anderen Systemen, und vielleicht auch bei einigen exotischen Dateisystemen unter unix, funktioniert das meines Wissens so nicht.
Das wuerde funktionieren, wenn ich die Datei vorm schreiben an der passenden Stelle teile und danach wieder zusammenfuege. Geht das ohne die Datei einzulesen (die Dateien koennen mehrere 100MB bis > 1GB gross sein)?
PS: die Größe der einzufuegenden Daten ist immer 1MB, falls das wichtig sein koennte.
Muss das wirklich eine einzelne grosse Datei sein? Würde es sich nicht anbieten, aus jedem dieser 1MB Stücke jeweils eine eigene Datei zu machen, und irgendwie einen Index darüber zu führen? Da scheint ja jedesmal eine in sich abgeschlossene "Einheit" Daten enthalten zu sein. Ob bei dieser Grösse der Overhead von zusätzlichen open()s noch/schon einen signifikanten Einfluss auf die Performance hat, müsstest du ggf. ausprobieren, das kann auch je nach System variieren. Die Suchbewegungen des Lesekopfes auf der Platte sind nach 1MB vernachlässigbar. Und bei denjenigen Dateisystemen, welche fragmentieren können, machst du dich vom aktuellen Zustand der Platte so auch weniger abhängig. -schorsch -- Georg Mischler -- simulations developer -- schorsch at schorsch com +schorsch.com+ -- lighting design tools -- http://www.schorsch.com/ _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
Hi Am 21.04.2004 14:32:14 schrieb Georg Mischler:
Nein. Oder soll das System die existierenden Daten auf der Platte rumschieben?
Ok, macht wirklich nicht viel Sinn. Denkbar waere, das man an den Clustergrenzen Daten einfuegen koennte, aber da wuerde ja selbst ein ext2 fragmentieren...
Unter unix kannst du ein seek() über das Dateiende hinausmachen, wodurch automatisch alles bis zu deiner neuen Position mit \0 gefüllt wird. Das Dateisystem alloziert für Blocks (Grösse variiert), in die du nichts geschrieben hast, auch keinen Platz auf der Platte. Erst wenn du dort das erste mal tatsächlich etwas hinschreibst (und seien es lauter explizite \0), wird physikalisch Raum beansprucht.
Meinst du soetwas hier? FileSize = 1048576 f = open('test.txt', 'w') f.seek(FileSize - 1) f.write('.') f.close() Das erzeugt bei mir (XP, getestet auf FAT32 und NTFS) eine 1MB grosse Datei.
Unter anderen Systemen, und vielleicht auch bei einigen exotischen Dateisystemen unter unix, funktioniert das meines Wissens so nicht.
Ich kann mich also nicht drauf verlassen, dass die obige Methode auf jedem Dateisystem funktioniert? Oder wovon ist das abhaengig?
Muss das wirklich eine einzelne grosse Datei sein? Würde es sich nicht anbieten, aus jedem dieser 1MB Stücke jeweils eine eigene Datei zu machen, und irgendwie einen Index darüber zu führen? Da scheint ja jedesmal eine in sich abgeschlossene "Einheit" Daten enthalten zu sein.
Also die Daten gehoeren schon zu einer Datei. Aber ich bekomme die Datei nur in Bloecken (halt diese 1MB grossen Daten). Die Reihenfolge, in der die Bloecke ankommen ist nicht garantiert, aber die Position ist bekannt.
Ob bei dieser Grösse der Overhead von zusätzlichen open()s noch/schon einen signifikanten Einfluss auf die Performance hat, müsstest du ggf. ausprobieren, das kann auch je nach System variieren.
Mit der obigen Methode dauert das erzeugen einer 700MB grossen Datei, 700 1MB oder 70 10MB grossen Dateien PiMalDaumen gleich lang. Von daher waere das egal, aber ich glaub nicht das ich soviele Dateien auf Platte haben will. Aber das bringt mich auf eine Idee: Man koennte die Bloecke in einer "DBM-Datei" speichern, als Index wuerde ein str(BlockPos) dienen. Weiss jemand spontan, wie weit dabei die Geschwindigkeit beim schreiben und lesen einbrechen wuerde? Ich weiss, das haengt sicher sehr stark von der konkreten Implementierung des dbm-Moduls ab, aber so als Anhaltspunkt... thx & cu boesi -- So stellt sich der Atheist doch die #1671 : icq-intern Unsterblichkeit vor - Lokalverbot #73628288 : icq-extern auf dem Friedhof. boesi111 : aim i171 : reallife _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Alexander 'boesi' Bösecke wrote: | Ok, macht wirklich nicht viel Sinn. Denkbar waere, das man an den | Clustergrenzen Daten einfuegen koennte, aber da wuerde ja selbst ein | ext2 fragmentieren... Ext2 fragmentiert auch. Die Frage ist nur, wie stark. Es gibt meines wissens nach nur reiser4 welches sich selbst deframentiert. Alle modernen Dateisysteme fragmentieren halt weniger stark und der Einbruch der Performance ist weniger schlimm, aber das ändert am Problem nicht. Wenn du eine Datei Grö0e N anlegst, müssen N/BLOCKSIZE+C Blöcke alloziert werden. Wenn die Datei vergrößert wird, müssen Blöcke alloziert werden, auch wenn diese nicht in der nächsten Umgebung der vorigen Blöcke liegen. Jedes Dateisystem hat dieses Problem. Zwar wird in modernen Dateisystemen versucht immer so viel Platz zwischen den Dateien zu lassen, daß es weniger problematisch ist, aber mit der Zeit... Reiserfs4 besitzt dafür eine Art Daemon, den sogenannten Repacker. Er defragmentiert das Dateisystem während der Rechner unbeschäftigt ist. | Ich kann mich also nicht drauf verlassen, dass die obige Methode auf | jedem Dateisystem funktioniert? Oder wovon ist das abhaengig? Ich wüsste keines. Du kannst die grö0e auch am Anfang allozieren und später beschreiben. Gruß ~ Daniel - -- nihil me cirumdat .. . .. ... . . .. . ... . .. . ... . . . pgp key @ http://files.poelzi.org/pgp.txt ED80 E53D 5269 4BB1 1E73 3A53 CBF9 A421 0A7B 003D -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.4 (GNU/Linux) Comment: Using GnuPG with Debian - http://enigmail.mozdev.org iD8DBQFAh6gwy/mkIQp7AD0RAuhrAKCY0mhT/WaV5uLUjbB2/qUMj01u2gCgrE9G ejiOF81JoEs6ACSwChT3ZTc= =8xtM -----END PGP SIGNATURE----- _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
Alexander 'boesi' Bösecke wrote:
Georg Mischler schrieb:
Unter unix kannst du ein seek() über das Dateiende hinausmachen, wodurch automatisch alles bis zu deiner neuen Position mit \0 gefüllt wird. Das Dateisystem alloziert für Blocks (Grösse variiert), in die du nichts geschrieben hast, auch keinen Platz auf der Platte. Erst wenn du dort das erste mal tatsächlich etwas hinschreibst (und seien es lauter explizite \0), wird physikalisch Raum beansprucht.
Meinst du soetwas hier? FileSize = 1048576 f = open('test.txt', 'w') f.seek(FileSize - 1) f.write('.') f.close()
Das erzeugt bei mir (XP, getestet auf FAT32 und NTFS) eine 1MB grosse Datei.
Auch unter unix wird dir "ls" eine 1MB grosse Datei anzeigen. Mit "du" siehst du aber, dass sie physikalisch nur einen einzigen Block belegt (512-4096k, je nach Grösse des Dateisystems). Sobald du um unteren Bereich etwas reinschreibst, wird das Dateisystem die dazu notwendigen Blöcke ebenfalls allozieren. Es is theoretisch möglich, dass moderne Windows Dateisysteme (NTFS) so etwas auch unterstützen, aber ich habe keine Ahnung, wie man dort den Unterschied feststellen könnte.
Unter anderen Systemen, und vielleicht auch bei einigen exotischen Dateisystemen unter unix, funktioniert das meines Wissens so nicht.
Ich kann mich also nicht drauf verlassen, dass die obige Methode auf jedem Dateisystem funktioniert? Oder wovon ist das abhaengig?
Von der Unterstützung des Dateisystems. Das müsstest du ggf. mit jedem in Frage kommenden System ausprobieren.
Muss das wirklich eine einzelne grosse Datei sein? ...
Also die Daten gehoeren schon zu einer Datei.
Warum?
Mit der obigen Methode dauert das erzeugen einer 700MB grossen Datei, 700 1MB oder 70 10MB grossen Dateien PiMalDaumen gleich lang.
Das ist auch genau die Strategie der meisten unix Dateisysteme. Fragmentierung lässt sich nie grundsätzlich verhindern. Aber wenn ich dafür sorge, dass nach Möglichkeit immer mindestens z.B. 1MB am Stück geschrieben/gelesen werden können, dann sind die negativen Effekte vernachlässigbar. Bei fast voller Platte lässt sich natürlich nicht mehr viel machen (wie Daniel schon erwähnt hat).
Von daher waere das egal, aber ich glaub nicht das ich soviele Dateien auf Platte haben will.
Warum nicht? Pack sie halt in ein extra Verzeichnis, dann ist die Liste aus dem Blickfeld. Am Ende sind doch alles nur Sektoren auf der Platte. Du hast zwar geringfügig mehr Arbeit, aber du musst dich zum Platzsparen nicht auf die Hilfe des Dateisystems verlassen, und es ist auch ohne interne Listen gleich offensichtlich, welche Teile der Daten schon existieren.
Aber das bringt mich auf eine Idee: Man koennte die Bloecke in einer "DBM-Datei" speichern, als Index wuerde ein str(BlockPos) dienen. Weiss jemand spontan, wie weit dabei die Geschwindigkeit beim schreiben und lesen einbrechen wuerde?
Das musst du ausprobieren, aber für eine letzten Endes lineare Sequenz von Datenblöcken scheint mir das Overkill zu sein. -schorsch -- Georg Mischler -- simulations developer -- schorsch at schorsch com +schorsch.com+ -- lighting design tools -- http://www.schorsch.com/ _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
Hi Sorry, dass ich erst jetzt antworte, aber ich war in den letzten Tagen etwas zu tief in meinem Projekt eingetaucht. Am 22.04.2004 14:32:57 schrieb Georg Mischler:
Auch unter unix wird dir "ls" eine 1MB grosse Datei anzeigen. Mit "du" siehst du aber, dass sie physikalisch nur einen einzigen Block belegt (512-4096k, je nach Grösse des Dateisystems). Sobald du um unteren Bereich etwas reinschreibst, wird das Dateisystem die dazu notwendigen Blöcke ebenfalls allozieren.
Aber genau das tu ich ja mit dem file.write('.'). Das braeuchte ich dann also unter Unix gar nicht und ls wuerde trotzdem eine Groesse von 1MB anzeigen? Windows alloziert die Bloecke auch erst, wenn man etwas in die Datei schreibt, aber davor ist die Datei 0 Byte gross (also auch nach dem file.close()). Sorry das ich so bloed frag, aber ich kann das hier nicht selber testen.
Es is theoretisch möglich, dass moderne Windows Dateisysteme (NTFS) so etwas auch unterstützen, aber ich habe keine Ahnung, wie man dort den Unterschied feststellen könnte.
So wie ich das sehe, haengt unter Windows die Dateigroesse immer von der Zahl der allozierten Bloecke ab.
Also die Daten gehoeren schon zu einer Datei.
Warum?
Dazu muss ich etwas weiter ausholen. Ich schreibe im Rahmen meiner Studienarbeit ein P2P-System. Ich hab eine zentrale Struktur aehnlich wie Napster gewaehlt - es gibt einen Server, Peers und Clients. Die Peers teilen dem Server mit welche Teile (genau diese 1MB grossen Bloecke) von welchen Dateien sie gespeichert haben. Der Client fragt beim Server nach einer bestimmten Datei und teilt diesem mit, welche Bloecke er bereits hat. Der Server entscheidet dann nach verschiedenen Kriterien, welche Bloecke der Client als naechstes von den Peers laedt. Der Client bekommt also auf die Anfrage eine Liste von Bloecken und dazu passend eine Liste von Peers, welche die Bloecke jeweils gespeichert haben. Wenn der Client diese Bloecke komplett hat, schreibt er sie auf Platte und bietet sie wiederum selbst als Peer an. Deswegen gehoeren die Bloecke zu einer Datei und deswegen ist die Reihenfolge, in welcher die Bloecke eintreffen, nicht festgelegt. Und aus diesem Grund will ich auch nicht wirklich x Dateien fuer eine Datei haben. Und einen Index fuer die Dateien brauch ich sowieso, weil ich noch ein paar zusaetzliche Infos benoetige, die in einem shelve gespeichert werden.
Das musst du ausprobieren, aber für eine letzten Endes lineare Sequenz von Datenblöcken scheint mir das Overkill zu sein.
Jup, da hast du wohl recht cu boesi -- baka baka #1671 : icq-intern #73628288 : icq-extern boesi111 : aim i171 : reallife _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
Alexander 'boesi' Bösecke wrote:
Am 22.04.2004 14:32:57 schrieb Georg Mischler:
Auch unter unix wird dir "ls" eine 1MB grosse Datei anzeigen. Mit "du" siehst du aber, dass sie physikalisch nur einen einzigen Block belegt (512-4096k, je nach Grösse des Dateisystems). Sobald du um unteren Bereich etwas reinschreibst, wird das Dateisystem die dazu notwendigen Blöcke ebenfalls allozieren.
Aber genau das tu ich ja mit dem file.write('.'). Das braeuchte ich dann also unter Unix gar nicht und ls wuerde trotzdem eine Groesse von 1MB anzeigen?
Solange du nichts schreibst, zeigt ls auch unter unix 0 bytes an. Wenn du irgendwo ein Zeichen reinschreibst, dann zeigt ls eine Grösse bis hinter der Position dieses Zeichens an. Mit du siehst du aber, dass nur ein kleiner Bruchteil davon wirklich belegt wird (auf meiner 18Gb reiser-Partition z.B. 6kb).
f = open('testfile', 'w') f.seek(1000000) f.write('.') f.close()
$> ls -l testfile -rw-r--r-- 1 gm users 1000001 2004-04-27 22:49 testfile $> du -k testfile 6 testfile Wenn ich anschliessend nochmal in der Mitte etwas reinschreibe, dann ändert sich die Grösse für ls nicht, du wird aber dann 12k anzeigen (nochmal 6k für einen zweiten Block).
Windows alloziert die Bloecke auch erst, wenn man etwas in die Datei schreibt, aber davor ist die Datei 0 Byte gross (also auch nach dem file.close()).
Ja klar, aber wieviele Blöcke werden dann alloziert? Nur einer oder gleich für die ganze Datei?
Dazu muss ich etwas weiter ausholen. Ich schreibe im Rahmen meiner Studienarbeit ein P2P-System. Ich hab eine zentrale Struktur aehnlich wie Napster gewaehlt - es gibt einen Server, Peers und Clients.
Eine Reimplmentation von BitTorrent? Schau doch mal, wie das dort gelöst ist. Zumindest unter unix wird da genau diese Eigenschaft des Dateisystems ausgenützt. -schorsch -- Georg Mischler -- simulations developer -- schorsch at schorsch com +schorsch.com+ -- lighting design tools -- http://www.schorsch.com/ _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
participants (3)
-
Alexander 'boesi' Bösecke
-
daniel.poelzleithner
-
Georg Mischler