python-Struktur "packen erfordert ein bytes-Objekt-Länge 8", während die Umwandlung von binay zu schweben
Ich bin derzeit versuchen, um Binärdateien in den Wagen und Umgekehrt über das struct-Modul. Meine Funktion arbeitet mit bestimmten Werten, wie 2.0 oder 14.0, aber es funktioniert nicht mit Werten wie 1.0.
Ich habe den code aus einer anderen Frage, und verändert es von python2 auf Python ist3.
import struct
def bin_to_float(b):
""" convert binary string to float """
bf = int_to_bytes(int(b, 2), 8) # 8 bytes needed for IEEE 754 binary64
bf = bytes(bf, 'UTF-8')
print(bf)
return struct.unpack('<d', bf)[0]
def int_to_bytes(n, minlen): # helper function
""" int/long to byte string """
nbits = n.bit_length() + (1 if n < 0 else 0) # plus one for any sign bit
nbytes = (nbits+7)//8 # number of whole bytes
bytes = []
for i in range(nbytes):
bytes.append(chr(n & 0xff))
n >>= 8
# zero pad if needed
if minlen > 0 and len(bytes) < minlen:
bytes.extend((minlen-len(bytes)) * '0')
bytes.reverse() # put high bytes at beginning
return ''.join(bytes)
# tests
def float_to_bin(f):
""" convert float to binary string """
ba = struct.pack('>d', f)
s = ''.join('{:08b}'.format(b) for b in ba)
# strip off leading zeros
for i in range(len(s)):
if s[i] != '0':
break
else: # all zeros
s = '0'
i = 0
return s[i:]
import math
floats = [2.0, 1.0, -14.0, 12.546, math.pi]
for f in floats:
binary = float_to_bin(f)
print ('float_to_bin(%f): %r' % (f, binary))
float = bin_to_float(binary)
print ('bin_to_float(%r): %f' % (binary, float))
print ()
Das problem scheint zu sein, dass ich beim codieren des str in bytes, bekomme ich 9 bytes statt 8, aber das passiert nur manchmal. Dies ist die Konsole Lesungen:
float_to_bin(2.000000): '100000000000000000000000000000000000000000000000000000000000000'
b'@\x00\x00\x00\x00\x00\x00\x00'
bin_to_float('100000000000000000000000000000000000000000000000000000000000000'): 0.000000
float_to_bin(1.000000): '11111111110000000000000000000000000000000000000000000000000000'
b'?\xc3\xb0\x00\x00\x00\x00\x00\x00'
Traceback (most recent call last):
File "C:/Users/arzuffi pc test/Desktop/prova struct.py", line 47, in <module>
float = bin_to_float(binary)
File "C:/Users/arzuffi pc test/Desktop/prova struct.py", line 8, in bin_to_float
return struct.unpack('<d', bf)[0]
struct.error: unpack requires a bytes object of length 8
Ich kann nicht scheinen, um herauszufinden, warum dies geschieht und wie Sie zu verhindern :/
Jemand weiß, warum das so ist?
Vielen Dank im Voraus.
EDIT: J. J. Hakala, antwortete genial, also ich poste die Antwort bis hier:
import struct
def bin_to_float(b):
""" convert binary string to float """
return struct.unpack('<d', struct.pack('<Q', int(b, 2)))[0]
def float_to_bin(f):
""" convert float to binary string """
return '{:b}'.format(struct.unpack('<Q', struct.pack('<d', f))[0])
Wenn jemand will, das gleiche zu tun mit 32 bit float, dies sollte gut sein:
import struct
def bin_to_float(b):
""" convert binary string to float """
return struct.unpack('<f', struct.pack('<L', int(b, 2)))[0]
def float_to_bin(f):
""" convert float to binary string """
return '{:b}'.format(struct.unpack('<L', struct.pack('<f',f))[0])
Vielen Dank allerseits!!!
int_to_bytes
zu sein scheint, mit Unicode-strings statt byte-strings.- Seite-Hinweis: die Verwendung
bytes
wie ein Variablenname ist eine schreckliche Idee, die Sie selbst mit Hilfe des built-inbytes
anderswo; wenn Sie es benötigt, in der gleichen Funktion, die Sie nicht haben, das original und Sie würden sich komische Fehler). bytes = bytearray()
könnte geeigneter sein, dannbytes = []
. Mit der bytearray -bytes(bf, 'UTF-8')
vermieden werden können.
Du musst angemeldet sein, um einen Kommentar abzugeben.
struct.pack /struct.entpacken könnte verwendet werden, um die Funktionen implementiert, wie dies
Als für die ursprüngliche Frage,
scheint der Täter sein, denn es kann ändern Sie die Länge der bf.
bin
mit'{:b}.format
(oder schneiden Ihnen die ersten beiden Zeichen derbin
's Ergebnis, und das scheint weniger elegant zu mir) oderfloat_to_bin
wieder'0bXXXX'
, wenn Sie wollen'XXXX'
. Ansonsten, ja, ich denke, ich mag diese Antwort besser als meine (ich bin der upvote jetzt), dastruct
Verpackung macht für einfacher code. Könnte auchint.to_bytes
undint.from_bytes
wenn Sie bevorzugt (nützlich für beliebige Längen, obwohl es nicht gelten, wenn das Ziel ist, zu konvertierendouble
Darstellungen, die Feste Länge).'{:b}'.format
wäre besser{:064b}
, so dass der Ausgabe-string immer die Länge 64. (Nachdem alle, ist es am besten gedacht als ein bit-string der Länge 64, anstatt eine ganze Zahl.)Nicht sicher, warum Sie gehen, um all diese Probleme wirklich. Es gibt viel einfachere Möglichkeiten zum ausführen dieser Art der Umwandlung:
Könnte es noch kürzer, aber ich wollte die Arbeit einschränken auf jeder Linie der Veranschaulichung.
Die genaue Ursache des Problems ist ein wenig unklar, aber der ständige Wechsel zwischen
bytes
undstr
, und der trickiness der Polsterung und unpadding richtig, die möglichen off-by-one Fehler in Sachen, wie die Berechnung der genauen bit-und byte-Längen, etc. könnte alles Durcheinander dieses oben. Der obige code macht die Arbeit viel mehr direkt und tragbar, ohne dass man mit der nitty gritty.ctypes
in Python nicht kompiliert, und solche microoptimizations nicht ein Faktor, der zu meiner Kenntnis. Die Ergebnisse - Plattform-abhängig, aber das Ziel ist es, die raw-binary-Darstellung einerdouble
, so plattformabhängig ist irgendwie der springende Punkt.Wenn Sie über die Struktur, in der Lagerung Wert in die binäre Datei, um zu vermeiden,
können Sie dies tun.
Hier size_ ist eine variable hängt von der Größe, die Sie packen.
Da Sie immer
size_ = 8.