Seite 1 von 1

File bytweise einlesen? (2.5.x)

Verfasst: Mittwoch 31. März 2010, 09:49
von mantus
Hi

irgendwie steig ich noch nicht ganz hinter die "leichtigkeit" von Python.

sobald man genaueren zugriff auf bytes haben will happerts bei mir irgendwie.

Also was ich machen will ist folgendes

ich muss ein file einlesen (binärdaten)
vorne an diesen datenstrom soll dann noch ein von mir deffinierter Header kommen.
und diesen Datanstrom muss ich dann all datenbuffer eine C Funktion zur verfügung stellen.

bei mir fehlts aber schon an den Grundlagen

wie lese ich eine Binärdatei byteweise ein?

Code: Alles auswählen

aList = []
aList.append(0x00)
aList.append(0x01)
aList.append(0xAF)
aList.append(0xFE)
while ???:
    aList.append(file.read(1))
ich finde kein "EOF" wie stelle ich da die richtige Abbruchbedingung

und wie deffiniere ich in python ein Byte?
wird mit apped(0x00) auch wirklich nur ein byte angefügt?

tia

Verfasst: Mittwoch 31. März 2010, 09:52
von EyDu
Hallo.

Das steht doch in der Dokumentation ;-)

Sebastian

Re: File bytweise einlesen? (2.5.x)

Verfasst: Mittwoch 31. März 2010, 10:14
von Darii
mantus hat geschrieben:und wie deffiniere ich in python ein Byte?
wird mit apped(0x00) auch wirklich nur ein byte angefügt?
Da Python kein Byte-Datentyp kennt, musst du je nach Anwendungszweck entweder mit 1-elementigen Strings(jedes Element eines Python-Strings ist ein char bzw. byte) oder Integern arbeiten. 0x00 gibt einen Integer.

Verfasst: Mittwoch 31. März 2010, 10:22
von BlackJack
@mantus: Und wenn Du in einer Schleife die einzelnen Bytes einliest und erst einmal nur an eine Liste hängst, dann frage ich mich warum Du sie überhaupt *einzeln* einliest. Das ist nämlich furchtbar langsam im Gegensatz zu einem kompletten Einlesen der Daten.

Was willst Du denn *eigentlich* machen? Warum geht kein ``data = '\x00\x01\xAF\xFE' + bin_file.read()``?

Verfasst: Mittwoch 31. März 2010, 10:38
von ms4py
Ich teile eigentlich die Bedenken der anderen, aber hier mal ein Ansatz:

Code: Alles auswählen

with open(filename, 'rb') as fobj:
  byte = fobj.read(1)
  while byte:
    process(byte)
    byte = fobj.read(1)
Das "byte" ist hierbei ein Char. Mit "ord(byte)" bekommst du einen Integer.

Verfasst: Mittwoch 31. März 2010, 10:47
von mantus
BlackJack hat geschrieben: Was willst Du denn *eigentlich* machen? Warum geht kein ``data = '\x00\x01\xAF\xFE' + bin_file.read()``?
ganz einfach weil ich es nicht wusste ;)
mein neuer Code schaut jetzt so aus

Code: Alles auswählen

        file = open(self.ui.getFilePath(),'r')
        binData = []
        binData.append(0x01)                          # Byte 0 = WriteCommand
        binData.append(len(file.name))                # Byte 1 = Size of filename
        binData.append(file.tell())                   # Byte 2 = Size of file
        binData.append(file.name)
        binData.append(file.read()) 
jetzt fehlt nur noch die grösse des Files

ehrlich gesagt find ich python zwar toll, aber wenn man solche streams zusammensetzen muss, wo man sicherstellen muss das jede Byte auch wirklich das Byte is das es sein muss, find ich CPP doch um welten einfacher :/ .... aber das liegt wohl eher an meinem begrenzent wissen über python.

auch bei den längen bin ich mir ned sicher
ich brauche die Länge des filenamen in 4 byte blöcken
in C mach ich einfach
nFilenameLen = (strlen("license.lic")+4)/4*4;
aber was mach ich in python?

und was da rauskommt wenn ich es via print ausgebe, schaut mir alles andere als richtig aus :/, mehr wie eine Liste, weniger wie ein bytearray :/

ich find leider auch keine tud's die sich damit beschäftigen.
und Bytearrays gibts ja leider erst ab 2.6 und das kann ich nicht einsetzen.

Verfasst: Mittwoch 31. März 2010, 10:52
von snafu
@ms4py:

Das, was du da zeigst, ist viel zu kompliziert. Du kannst in einem Schwung über die Zeichen iterieren, die `read()` zurückgibt. Unter der Annahme, dass man beim `ord()` bleibt und ich die geöffnete Datei mal durch einen "Pseudo-Stream" ersetze, sähe das Ganze dann so aus:

Code: Alles auswählen

In [1]: from StringIO import StringIO

In [2]: stream = StringIO('foobar')

In [3]: map(ord, stream.read())
Out[3]: [102, 111, 111, 98, 97, 114]

Verfasst: Mittwoch 31. März 2010, 11:06
von BlackJack
@mantus: Das ist in der Tat eine Liste. Was hättest Du denn auch anderes erwartet bei dem Code!? Und was genau *brauchst* Du denn am Ende? *Eine* Zeichenkette mit den Binärdaten?

Und wie sieht die Spezifikation für so einen "Stream" aus? Ich kann mir schlecht vorstellen, dass der nur Dateigrössen bis 255 Bytes erlaubt!? Wenn nicht, dann müsste man mal klären wie die Zahlen mit den/der Grössenangabe(n) am Anfang kodiert sein sollen.

Für die Dateigrösse schau Dir mal die Funktionen in `os.path` an.

Wenn Du weist wie man die Länge in "Vierer-Blöcken" in C berechnet, sehe ich das Problen in Python irgendwie nicht.

Muss der Dateiname dann aber nicht auch auf diese Länge aufgefüllt werden? Sonst sehe ich da Probleme mit der Eindeutigkeit der Daten.

Verfasst: Mittwoch 31. März 2010, 11:46
von HWK
Ein Beispiel:

Code: Alles auswählen

>>> import StringIO
>>> import struct
>>> stream = StringIO.StringIO('foobar')
>>> stream.seek(0, 2)
>>> file_len = stream.tell()
>>> stream.seek(0)
>>> fn = 'MyFile'
>>> fn_len = (len(fn) + 3) / 4 * 4
>>> fn += (fn_len - len(fn)) * '\x00'
>>> struct.pack('BLL', 1, fn_len, file_len) + fn + stream.read()
'\x01\x00\x00\x00\x08\x00\x00\x00\x06\x00\x00\x00MyFile\x00\x00foobar'
MfG
HWK

Verfasst: Mittwoch 31. März 2010, 12:13
von mantus
Danke HWK das klingt schonmal sehr gut, werd das gleich versuchen einzubaun.
"StringIO2 kannte ich z.b. leider garnicht.

was ich habe ist
filename als String
was ich erzeugen will ist folgendes:
Bytestream
byte 0 = Mode = 1
byte 1 = size of filename in multibles of 4Byte (ende finden is trotzdem einfach da er 0 terminiert sein muss)
byte 2,3,4,5 = Size of file (wie von z.b. ftell)
bytes 6+ = bin data of file

in C hatte ich das innerhalb von kürzester Zeit, aber in pyhton reicht anscheinend mein wissen nicht aus

@BalckJack "Wenn Du weist wie man die Länge in "Vierer-Blöcken" in C berechnet, sehe ich das Problen in Python irgendwie nicht. "
ich schon, python ändert ja dynamisch immer seine datentypen
X = (7+3)/4 ... in C ergibt das für einen integer 2, für ein double 2.5 .... was ergibt es in python? ... was passiert jetzt wenn ich .append((7+3)/4) mache ?

Verfasst: Mittwoch 31. März 2010, 12:29
von BlackJack
@mantus: `StringIO` brauchst Du nicht, das wurde hier ja nur verwendet um mal eben eine Datei im Speicher zu simulieren und keine echte auf Platte anlegen zu müssen.

Bei der Beschreibung des Formats hast Du den Dateinamen jetzt ausgelassen.

Python ändert nicht dynamisch seine Datentypen. Jedes Objekt hat einen festen Datentyp (solange man nicht hässliche Hacks verwendet). ``(7+3)/4`` ergibt in Python 2 weil alle beteiligten Objeke den Typ `int` haben. Und das gibt auch in C *immer* 2 egal welchen Typ `X` hat. An der Stelle unterscheiden sich C und Python nicht. Solange alle beteiligten Werte den Typ `int` haben, sind auch die Zwischenergebnisse von dem Typ.

Wenn es übrigens um echte Dateien geht, dann würde ich `os.path.getsize()` der "Akrobatik" mit `seek()` vorziehen. Das ist kürzer und IMHO klarer.

Verfasst: Mittwoch 31. März 2010, 12:32
von mantus
also code schaut jetzt wie folgt aus

Code: Alles auswählen

        file = open(self.ui.getFilePath(),'r')
        file.seek(0, 2)
        file_len = file.tell()
        file.seek(0)
        fn_len = (len(fileName) + 3) / 4 * 4
        fileName += (fn_len - len(fileName)) * '\x00'
        stream = struct.pack('BLL', 1, fn_len, file_len) + fileName + file.read()
optischer check des outputs schaut bis jetzt gut aus, ich dank euch für die hilfe hier her.