Lesen einer vollständigen Binärdatei in Python

8

Ich muss eine Binärdatei von Python importieren - der Inhalt ist 16-Bit-Ganzzahlen, Big-Endian.

Die folgenden Stack-Overflow-Fragen schlagen vor, wie mehrere Bytes gleichzeitig abgerufen werden können, aber ist dies der Weg, um eine ganze Datei einzulesen?

Ich dachte, eine Funktion wie folgt zu erstellen:

%Vor%

Aber das ist ziemlich langsam (die Datei ist 165924350 Bytes). Gibt es einen besseren Weg?

    
hatmatrix 12.12.2010, 19:47
quelle

5 Antworten

4

Ich würde direkt lesen, bis EOF (es bedeutet, auf den Erhalt einer leeren Zeichenfolge zu prüfen), Entfernen dann die Notwendigkeit, range () und getsize zu verwenden.
Alternativ sollte die Verwendung von xrange (anstelle von range ) Dinge verbessern, insbesondere für die Speichernutzung.
Darüber hinaus, wie Falmarri vorgeschlagen hat, würde das Lesen von mehr Daten zur selben Zeit die Leistung ziemlich verbessern.

Das heißt, ich würde keine Wunder erwarten, auch weil ich nicht sicher bin, ob eine Liste die effizienteste Möglichkeit ist, all diese Datenmengen zu speichern.
Was ist mit der Verwendung von NumPy's Array und seinen Möglichkeiten, binäre Dateien zu lesen / schreiben ? In diesem Link gibt es einen Abschnitt über das Lesen roher Binärdateien mit numpyio.fread. Ich glaube, das sollte genau das sein, was Sie brauchen.

Hinweis: Ich persönlich habe NumPy nie benutzt; Sein Hauptgrund ist jedoch der genaue Umgang mit großen Datenmengen - und genau das machen Sie in Ihrer Frage.

    
Roberto Liffredo 12.12.2010, 20:01
quelle
9

Verwenden Sie numpy.fromfile .

    
Karl Knechtel 12.12.2010 20:02
quelle
2

Sie lesen und entpacken 2 Bytes gleichzeitig

%Vor%

Warum liest du nicht gleich 1024 Bytes gleichzeitig?

    
Falmarri 12.12.2010 19:56
quelle
2

Ich hatte die gleiche Art von Problem, obwohl ich in meinem speziellen Fall eine sehr seltsame Datei im Binärformat (500 MB) mit verschachtelten Blöcken von 166 Elementen, die vorzeichenbehaftete 3-Byte-Ganzzahlen waren, konvertieren musste; Ich hatte also auch das Problem, von 24-Bit- zu 32-Bit-Ganzzahlen mit Vorzeichen zu konvertieren, die die Dinge etwas verlangsamen.

Ich habe es gelöst mit NumPy's memmap (es ist nur eine praktische Möglichkeit, Pythons memmap zu verwenden) und struct.unpack auf einem großen Teil der Datei.

Mit dieser Lösung kann ich die gesamte Datei in ungefähr 90 Sekunden konvertieren (lesen, machen und auf Platte schreiben) (zeitlich abgestimmt mit time.clock ()).

Ich könnte einen Teil des Codes hochladen.

    
RobiC 06.07.2012 08:22
quelle
1

Ich denke, der Flaschenhals, den Sie hier haben, ist zweifach.

Je nach Betriebssystem und Festplattencontroller werden die Aufrufe von f.read(2) mit f , die eine große Datei darstellen, normalerweise effizient gepuffert - normalerweise . Mit anderen Worten, das Betriebssystem liest einen oder zwei Sektoren (mit Plattensektoren normalerweise mehrere KB) von der Platte in den Speicher, weil dies nicht viel teurer ist als das Lesen von 2 Bytes aus dieser Datei. Die zusätzlichen Bytes werden effizient im Speicher zwischengespeichert, bereit für den nächsten Aufruf, um diese Datei zu lesen. Verlassen Sie sich nicht auf dieses Verhalten - es könnte Ihr Engpass sein - aber ich denke, es gibt andere Probleme hier.

Ich mache mir mehr Gedanken über die Konvertierungen einzelner Bytes in kurze und einzelne Aufrufe in numpy. Diese werden überhaupt nicht zwischengespeichert. Sie können alle Shorts in einer Python-Liste von Ints behalten und die ganze Liste in numpy umwandeln, wenn (und wenn) benötigt wird. Sie können auch einen einzelnen Aufruf struct.unpack_from ausführen, um alles in einem Puffer zu konvertieren.

Überlegen Sie:

%Vor%

Ich habe eine Datei zufälliger kurzer signierter Bytes von 165.924.350 Bytes (158.24 MB) erstellt, die zu 82.962.175 signierten 2-Byte-Kurzschlüssen gehören. Mit dieser Datei habe ich die Funktion read_wopper oben ausgeführt und sie lief:

%Vor%

Wenn Sie nicht brauchen, wird die Funktion in 6 Sekunden ausgeführt. All dies auf OS X, Python 2.6.1 64 Bit, 2.93 GHz Core i7, 8 GB RAM. Wenn Sie buf_size=1024*2 in read_wopper in buf_size=2**16 ändern, lautet die Laufzeit:

%Vor%

Ihr größter Flaschenhals, denke ich, sind die einzelnen Byte-Aufrufe zum Entpacken - nicht Ihr 2 Byte liest von der Disc. Sie möchten vielleicht sicherstellen, dass Ihre Datendateien nicht fragmentiert sind und wenn Sie OS X verwenden, dass Ihre freier Speicherplatz auf der Festplatte (und hier ) ist nicht fragmentiert.

Bearbeiten Ich habe den gesamten zu erstellenden Code gepostet und lese dann eine binäre Datei mit Ints. Auf meinem iMac bekomme ich immer & lt; 15 Sekunden, um die Datei von zufälligen Ints zu lesen. Es dauert etwa 1:23, um zu erstellen, da die Kreation eine kurze zu einer Zeit ist.

    
the wolf 13.12.2010 06:20
quelle

Tags und Links