File bytweise einlesen? (2.5.x)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mantus
User
Beiträge: 17
Registriert: Freitag 4. Dezember 2009, 09:08

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
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Das steht doch in der Dokumentation ;-)

Sebastian
Das Leben ist wie ein Tennisball.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

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.
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()``?
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

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.
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
mantus
User
Beiträge: 17
Registriert: Freitag 4. Dezember 2009, 09:08

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.
Benutzeravatar
snafu
User
Beiträge: 6732
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@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]
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.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

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
mantus
User
Beiträge: 17
Registriert: Freitag 4. Dezember 2009, 09:08

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 ?
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.
mantus
User
Beiträge: 17
Registriert: Freitag 4. Dezember 2009, 09:08

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.
Antworten