2016-07-21 2 views
1

Ich habe eine Binärdatei, die 4-Byte-Binärwerte enthält, die jeweils einen Satz von zwei short int darstellen. Ich weiß, dass ich einen einzigen 4-Byte-Binärwert in zwei kurze ganzen Zahlen wie folgt auspacken:Wie entpacke ich einen Binärdateipuffer in zwei Variablen?

from struct import unpack 

fval = b'\xba\x1e\x99\x01' #actualy read from some file 
qualdip, azi = unpack('hh', fval) 
print(type(qualdip), qualdip) 
print(type(azi), azi) 

>>> <class 'int'> 7866 
>>> <class 'int'> 409 

Nun, ich den gesamten Puffer entpacken möge. Im Moment mache ich:

qualdips = [] 
azis = [] 
with open(bfile, 'rb') as buf: 
    fval = buf.read(4) 
    while fval: 
     qualdip, azi = unpack('hh', fval) 
     azis.append(azi) 
     qualdips.append(qualdip) 
     fval = buf.read(4) 

, die eine Minute für eine 277MB-Datei übernimmt und scheint einen großen Speicher-Overhead zu erzeugen.

Ich möchte den gesamten Filebuffer direkt in die beiden Variablen entpacken. Wie erreiche ich das?

Ich vermute, dass struct.unpack_from ist mein Freund, aber ich bin mir nicht sicher, wie man das Format formulieren.

with open(bfile, 'rb') as buf: 
    qualdip, azi = unpack_from('hh', buf) 

extrahiert nur zwei Werte, und (ich weiß, die Anzahl der Elemente meiner Datei)

with open(bfile, 'rb') as buf: 
    qualdip, azi = unpack_from('72457091h72457091h', buf) 

erwartet diese lächerliche Menge an Ausgangsvariablen. Also:

Wie tun Ich entpacke den gesamten Dateipuffer direkt in die beiden Variablen?

+0

Haben Sie Ihren Code profiliert, um zu sehen, wo der Aufwand ist? Wenn die E/A-Vorgänge am längsten dauern, können Sie versuchen, die Datei in größeren Blöcken zu lesen. – theorifice

Antwort

1

Ich weiß nicht, einen Weg, um die Werte in zwei Listen direkt zu entpacken, aber Sie können die gesamte Datei in ein Tupel auszupacken und in Scheiben schneiden sie dann in zwei:

fval = b'\xba\x1e\x99\x01' * 3 
unpacked= unpack('3h3h', fval) 
qualdip = unpacked[0::2] 
azi = unpacked[1::2] 

Alternativ islice zum Erstellen eine iterator, die den Speicherverbrauch reduzieren wird.

qualdip = islice(unpacked, 0, None, 2) 
azi = islice(unpacked, 1, None, 2) 
+0

islice gibt nur das Iterator-Objekt zurück, aber ich brauche die tatsächlichen Werte. Das Schneiden funktioniert großartig. Ich benutze jetzt 'qualdip = unpacked [0 :: 2]', 'azi = unpacked [1 :: 2]'. – wsj

+0

Ich habe Ihre Antwort entsprechend bearbeitet, bin mir jedoch nicht sicher, wie ich die tatsächlichen Werte aus dem im zweiten Block der Antwort generierten islice-Objekt erhalten soll. – wsj

+0

@wsj 'islice' ist ein [generator object] (http://stackoverflow.com/documentation/python/292/generators-yield#t=201607221128531431962), über das Sie mit' for value in azi: 'oder iterieren können Holen Sie die Werte nacheinander mit 'next (azi)'. –

0

Ich denke, das könnte ein schneller Weg, es zu tun:

import os 
import struct 

def pairwise(iterable): 
    "s -> (s0,s1), (s2,s3), (s4, s5), ..." 
    a = iter(iterable) 
    return zip(a, a) 

bfile = 'bfile.bin' 
filesize = os.stat(bfile).st_size 
numvals = filesize // 2 

with open(bfile, 'rb') as bf: 
    fmt = '{}h'.format(numvals) 
    values = struct.unpack(fmt, str(bf.read())) 

qualdips, azis = zip(*pairwise(values)) 
Verwandte Themen