/ / Warum löst struct.unpack () eine Ausnahme aus, wenn meine Zeichenfolgen die richtige Länge haben? - Python, Struktur

Warum gibt struct.unpack () eine Ausnahme aus, wenn meine Strings die richtige Länge haben? - Python, Struktur

Ich habe eine Datei, in der einige Zeilen Metadaten sind, die ich ignorieren kann, und einige Zeilen sind die gedruckten Ergebnisse von struct.pack-Aufrufen. Angenommen, f.txt ist:

key: 3175
x00x00x00x00x00x00x00x00
key: 3266
x00x00x00x00x00x00x00x00

In diesem Fall sind die mit "key" beginnenden ZeilenDie Metadaten und die Byte-Zeichenfolgen sind die Werte, die ich extrahieren möchte. Auch in diesem Fall wurden die zwei Byte langen Zeilen mit struct.pack ("d", 0) erzeugt. Der folgende Code ist, was ich tun möchte:

import struct
for line in open("f.txt", "r"):
# if not metadata, remove newline character and unpack
if line[0:3] != "key":
val = struct.unpack("d", line[0:-1])
appendToList(val) # do something else with val

Damit erhalte ich: "struct.error: entpacken erfordert ein Stringargument der Länge 8".

Wenn wir den Code geringfügig ändern:

import struct
for line in open("f.txt", "r"):
# if not metadata, remove newline character and unpack
if line[0:3] != "key": print line[:-1]

dann ist die Ausgabe wie erwartet:

x00x00x00x00x00x00x00x00
x00x00x00x00x00x00x00x00

Wenn ich den Byte-String dann direkt in den Entpack-Aufruf stecke, habe ich Erfolg:

import struct
# successful unpacking
struct.unpack("d", "x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00")

Ich habe versucht, die folgenden Varianten der Linie zu entpacken, die alle das gleiche Ergebnis liefern:

str(line)
repr(line)
b"%s" % line

Antworten:

0 für die Antwort № 1

für deinen string in der txt datei:

x00x00x00x00x00x00x00x00

was in Python ist es eigentlich:

\x00\x00\x00\x00\x00\x00\x00\x00

Daher sollten Sie diesen String analysieren und konvertieren. Verwenden Sie für Ihr Beispiel den folgenden Code, um das zu erhalten, was Sie möchten:

s = line.strip().split("\x")
r = ""
for v in s:
if len(v) > 0:
print v
r += struct.pack("b", int(v, 16))
val = struct.unpack("d", r)[0]
print val

3 für die Antwort № 2

Die tatsächlichen Bytes in Ihrer Textdatei sind die Zeichenfolgen-geschützten Bytes, die an einer Python-Konsole angezeigt werden, nicht die von ihnen dargestellten binären Bytes.

Zum Beispiel enthält Ihre Textdatei x00 (vier Byte lang), nicht das Null-Byte (ein Byte lang).

Sie müssen diesen Text entschlüsseln (in eine binäre Form konvertieren), bevor struct daran arbeiten kann.

(BITTE BEACHTEN SIE, dass Ihr Dateiformat nicht sehr gut ist, da Sie möglicherweise eine Zeile haben könnten, die eine Zahl ist, aber mit "key:" beginnt! "key: x00x00x00" ist eine gültige Nummer 6.8388560679e-313! Wenn Sie bei jeder zweiten Zeile zwischen Metadaten und Werten wechseln, sollten Sie nur verfolgen, auf welcher Zeilennummer Sie sich befinden, und diese entsprechend analysieren.)

Hier gibt es eine viel einfachere Lösung als die anderen.

Python hat einen eingebauten Codec namens string_escape Damit werden Python-Escape-Codes in die von ihnen dargestellten binären Bytes konvertiert:

for line in thefile:
if line[0:3] != "key":
binaryline = line[:-1].decode("string_escape")
val = struct.unpack("d", binaryline)

Wenn Sie eine große Liste dieser doppelten Werte haben und diese effizient in einer Array-Struktur speichern möchten, ziehen Sie die Verwendung von in Betracht array Modul statt struct:

vals = array.array("d")

for line in thefile:
if line[0:3] != "key":
binaryline = line[:-1].decode("string_escape")
# appends binaryline to vals array, interpreting as a double
vals.fromstring(binaryline)