Ich frage eine Datenbank ab und archiviere die Ergebnisse mit Python, und ich versuche, die Daten zu komprimieren, während ich sie in die Protokolldateien schreibe. Ich habe ein paar Probleme damit.
Mein Code sieht so aus:
%Vor% Meine Ausgabedatei hat jedoch eine Größe von 1.409.780. Wenn bunzip2
für die Datei ausgeführt wird, wird eine Datei mit der Größe 943.634 erstellt, und wenn bzip2
ausgeführt wird, ergibt sich eine Größe von 217.275. Mit anderen Worten, die unkomprimierte Datei ist wesentlich kleiner als die mit Pythons bzip-Codec komprimierte Datei. Gibt es eine Möglichkeit, dies zu beheben, außer dass bzip2
in der Befehlszeile ausgeführt wird?
Ich habe Pythons gzip-Codec ausprobiert (indem ich die Zeile in codecs.open(archive_file, 'a+', 'zip')
änderte), um zu sehen, ob das Problem behoben wurde. Ich bekomme immer noch große Dateien, aber ich bekomme auch einen gzip: archive_file: not in gzip format
Fehler, wenn ich versuche, die Datei zu entpacken. Was ist dort los?
BEARBEITEN : Ich hatte die Datei ursprünglich im Append-Modus geöffnet, nicht im Schreibmodus. Während dies ein Problem sein kann oder nicht, bleibt die Frage bestehen, ob die Datei im 'w' Modus geöffnet ist.
Wie andere Poster festgestellt haben, ist das Problem, dass die Bibliothek codecs
nicht verwendet wird ein inkrementeller Kodierer zum Kodieren der Daten; Stattdessen codiert es jeden Datenschnipsel, der der Methode write
als komprimierter Block zugeführt wird. Das ist furchtbar ineffizient und nur eine schreckliche Designentscheidung für eine Bibliothek, die mit Streams arbeiten soll.
Die ironische Sache ist, dass es einen vollkommen vernünftigen inkrementellen bz2-Encoder gibt, der bereits in Python integriert ist. Es ist nicht schwer, eine "dateiähnliche" Klasse zu erstellen, die automatisch das Richtige tut.
%Vor% Ein Vorbehalt : In diesem Beispiel habe ich die Datei im Append-Modus geöffnet; Das Anhängen mehrerer komprimierter Streams an eine einzelne Datei funktioniert perfekt mit bunzip2
, aber Python selbst kann damit nicht umgehen (obwohl ein Patch ist dafür). Wenn Sie die komprimierten Dateien, die Sie in Python erstellen, lesen müssen, halten Sie sich an einen einzelnen Stream pro Datei.
Das Problem scheint zu sein, dass die Ausgabe auf jedes write()
geschrieben wird. Dadurch wird jede Zeile in einem eigenen bzip-Block komprimiert.
Ich würde versuchen, eine viel größere Zeichenfolge (oder eine Liste von Zeichenfolgen, wenn Sie sich Sorgen um die Leistung machen) im Speicher zu erstellen, bevor Sie sie in die Datei schreiben. Eine gute Größe für die Aufnahme wäre 900K (oder mehr), da dies die Blockgröße ist, die bzip2 verwendet
Das Problem liegt daran, dass Sie den Append-Modus verwenden, der zu Dateien führt, die mehrere komprimierte Datenblöcke enthalten. Schau dir dieses Beispiel an:
%Vor%Auf meinem System erzeugt dies eine 12 Byte große Datei. Mal sehen, was es enthält:
%Vor%Okay, jetzt machen wir einen weiteren Schreibvorgang im Append-Modus:
%Vor%Die Datei ist jetzt 24 Byte groß und ihr Inhalt lautet:
%Vor%Was hier passiert, ist, dass unzip einen einzelnen gezippten Stream erwartet. Sie müssen die Spezifikationen überprüfen, um zu sehen, was das offizielle Verhalten bei mehreren verketteten Streams ist, aber meiner Erfahrung nach verarbeiten sie das erste und ignorieren den Rest der Daten. Das macht Python.
Ich erwarte, dass bunzip2 dasselbe macht. In Wirklichkeit ist Ihre Datei komprimiert und viel kleiner als die darin enthaltenen Daten. Aber wenn du es durch bunzip2 durchführst, bekommst du nur die erste Menge von Aufzeichnungen zurück, die du ihm geschrieben hast; der Rest wird verworfen.
Ich bin mir nicht sicher, wie anders das ist, als wenn man Codecs macht, aber wenn man GzipFile vom gzip-Modul benutzt, kann man inkrementell an die Datei anhängen, aber es wird nicht sehr gut komprimiert, wenn man nicht viel davon schreibt Daten auf einmal (vielleicht & gt; 1 KB). Dies ist nur die Natur der Komprimierungsalgorithmen. Wenn die Daten, die Sie schreiben, nicht besonders wichtig sind (d. H. Sie können damit fertig werden, wenn Ihr Prozess stirbt), könnten Sie eine gepufferte GzipFile-Klasse schreiben, die die importierte Klasse umhüllt, die größere Datenblöcke ausgibt.
Tags und Links python gzip python-2.x bzip2