Python Datei Slurp w / Endian-Umwandlung
-
06-07-2019 - |
Frage
Es wurde vor kurzem gefragt , wie eine Datei schlürft in Python zu tun, und die akzeptierte Antwort vorgeschlagen etwas wie:
with open('x.txt') as x: f = x.read()
Wie würde ich mich dies zu tun, um die Datei in und wandelt die Endian-Darstellung der Daten zu lesen?
Zum Beispiel habe ich eine 1 GB binäre Datei, die als Big-Endian verpackt nur ein Haufen einfacher Genauigkeit Schwimmer ist und ich mag es wenig Endian konvertieren und Dump in eine numpy Array. Unten ist die Funktion, die ich dieses und einige echte Code zu erreichen, schrieb, die es nennt. Ich benutze struct.unpack
die Endian-Umwandlung tun und versucht, alles zu beschleunigen, indem mmap
verwendet wird.
Meine Frage ist dann, verwende ich die slurp richtig mit mmap
und struct.unpack
? Gibt es eine sauberen, schnellen Weg, dies zu tun? Gerade jetzt, was ich habe funktioniert, aber ich würde wirklich lernen, wie man dies besser zu tun.
Vielen Dank im Voraus!
#!/usr/bin/python
from struct import unpack
import mmap
import numpy as np
def mmapChannel(arrayName, fileName, channelNo, line_count, sample_count):
"""
We need to read in the asf internal file and convert it into a numpy array.
It is stored as a single row, and is binary. Thenumber of lines (rows), samples (columns),
and channels all come from the .meta text file
Also, internal format files are packed big endian, but most systems use little endian, so we need
to make that conversion as well.
Memory mapping seemed to improve the ingestion speed a bit
"""
# memory-map the file, size 0 means whole file
# length = line_count * sample_count * arrayName.itemsize
print "\tMemory Mapping..."
with open(fileName, "rb") as f:
map = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
map.seek(channelNo*line_count*sample_count*arrayName.itemsize)
for i in xrange(line_count*sample_count):
arrayName[0, i] = unpack('>f', map.read(arrayName.itemsize) )[0]
# Same method as above, just more verbose for the maintenance programmer.
# for i in xrange(line_count*sample_count): #row
# be_float = map.read(arrayName.itemsize) # arrayName.itemsize should be 4 for float32
# le_float = unpack('>f', be_float)[0] # > for big endian, < for little endian
# arrayName[0, i]= le_float
map.close()
return arrayName
print "Initializing the Amp HH HV, and Phase HH HV arrays..."
HHamp = np.ones((1, line_count*sample_count), dtype='float32')
HHphase = np.ones((1, line_count*sample_count), dtype='float32')
HVamp = np.ones((1, line_count*sample_count), dtype='float32')
HVphase = np.ones((1, line_count*sample_count), dtype='float32')
print "Ingesting HH_Amp..."
HHamp = mmapChannel(HHamp, 'ALPSRP042301700-P1.1__A.img', 0, line_count, sample_count)
print "Ingesting HH_phase..."
HHphase = mmapChannel(HHphase, 'ALPSRP042301700-P1.1__A.img', 1, line_count, sample_count)
print "Ingesting HV_AMP..."
HVamp = mmapChannel(HVamp, 'ALPSRP042301700-P1.1__A.img', 2, line_count, sample_count)
print "Ingesting HV_phase..."
HVphase = mmapChannel(HVphase, 'ALPSRP042301700-P1.1__A.img', 3, line_count, sample_count)
print "Reshaping...."
HHamp_orig = HHamp.reshape(line_count, -1)
HHphase_orig = HHphase.reshape(line_count, -1)
HVamp_orig = HVamp.reshape(line_count, -1)
HVphase_orig = HVphase.reshape(line_count, -1)
Lösung
with open(fileName, "rb") as f:
arrayName = numpy.fromfile(f, numpy.float32)
arrayName.byteswap(True)
Ziemlich schwer für Geschwindigkeit und Prägnanz zu schlagen ;-). Für byteswap siehe hier (das True
Argument bedeutet, "es an Ort und Stelle zu tun"); siehe hier .
Das funktioniert wie auf dem Little-Endian-Maschinen ist (da die Daten Big-Endian sind, wird die byteswap erforderlich). Sie können testen, ob das der Fall ist, die byteswap bedingt, ändern Sie die letzte Zeile von einem unbedingten Aufruf zu tun in byteswap, zum Beispiel:
if struct.pack('=f', 2.3) == struct.pack('<f', 2.3):
arrayName.byteswap(True)
d., Ein Anruf auf einen Test von little-Endian-bedingte byteswap.
Andere Tipps
Leicht modifizierte @ Alex Martelli Antwort :
arr = numpy.fromfile(filename, numpy.dtype('>f4'))
# no byteswap is needed regardless of endianess of the machine
Sie könnten Coble zusammen ein ASM-basierte Lösung mit CorePy . Ich frage mich aber, wenn Sie genug Leistung aus dem einem anderen Teil des Algorithmus zu gewinnen möglicherweise in der Lage. I / O und Manipulationen auf 1 GB Datenblöcke werden eine Weile dauern, die jemals, wie Sie es.
Eine andere Sache, die Sie hilfreich finden könnten wäre zu C wechseln, sobald Sie den Algorithmus in Python prototypisiert haben. Ich tue dies für Manipulationen auf einer ganze Welt DES (Höhe) Datensatz einmal. Das Ganze war viel erträglicher, wenn ich aus dem interpretierten Skript entkam.
Ich würde so etwas wie dies erwartet, schneller sein
arrayName[0] = unpack('>'+'f'*line_count*sample_count, map.read(arrayName.itemsize*line_count*sample_count))
Bitte verwenden Sie keine map
als Variablenname