ByteArray to IntegerList

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.
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

Moin,

ich muss einer fertigen Function (SPI.writebytes auf meinem Rasperry Pi) eine Liste mit Integerwerten übergeben.
Diese Integerliste darf/kann nicht mehr als 4096 Werte aufnehmen.

Die "Füllung" stammt aus einem File (GrafikFile mit Farbwerten pro Pixel).

Mit:

Code: Alles auswählen

def get_bytes_from_file(filename):  
    return open(filename, "rb").read()

def GetFileList(filename):
    FileData = get_bytes_from_file("75x108.bin")
    print FileData
hole ich die einzelnen Bytes in ein Array.....
Das klappt auch soweit......

Wie bekomme ich jetzt die Bytes aus FileData Blockweise (4096) in eine IntegerListe?


Gruß
Pf@nne
Sirius3
User
Beiträge: 18265
Registriert: Sonntag 21. Oktober 2012, 17:20

@Pf@nne: was ist eine IntegerListe? wie wäre es wenn Du jeweils Blöcke von 4096 Bytes lesen würdest?
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

Der SPI.WriteBytes-Befehl möchte eine Liste von Integerwerten [1, 255, 43, ...]

Blöcke lesen wäre OK, ich hab bloß noch nicht verstanden wie ich die gelesenen Daten in das o.g. Format bekomme.....

Gruß
Pf@nne
BlackJack

@Pf@nne: Musst Du denn da überhaupt irgend etwas konvertieren? Ein `bytearray` sollte es doch eigentlich auch tun.
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

Code: Alles auswählen

 spi.writebytes(FileData[0:100])
TypeError: Argument must be a list of at least one, but not more than 4096 integers
Der will immer eine Liste haben.....
BlackJack

@Pf@nne: Einfach `list()` drauf aufrufen sollte es tun.

Wirf mal einen Blick in den Style Guide for Python Code bezüglich der Namensgebung. Bei `FileData` denkt ein Python-Programmierer es handelt sich um einen Datentyp.
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

Code: Alles auswählen

spi.writebytes(list(FileData[0:100]))
TypeError: Argument must be a list of at least one, but not more than 4096 integers
List() liefert scheinbar Strings (Chars).....
['\xd6', 'x', '\xd6', '\x98', '\xd6', 'W', '\x9c', 'n', '\x8b', '\xcc', '\x83', '\xac', '\x83', '\x8b', '{', 'J', '{', ')', '{', 'I', '{', 'I', '{', 'I', '\x83', 'j', '\x83', 'j', '\x83', 'j', '\x83', '\x8a', '\x83', '\x8a', '\x83', '\x8b', '\x8b', '\xab', '\x83', '\xab', '\x8b', '\xcb', '\xa4', '\xb1', '\x9c', '\xb1', 'I', '\xc5', '(', '\xe2', '(', '\xe2', '0', '\xe2', '0', '\xe2', '0', '\xe2', '0', '\xe2', '1', '\x02', '1', '\x02', '1', '\x02', '1', '\x02', 'Z', 'h', '\xc5', '\xd5', '\xd6', '7', '\xde', '\x99', '\xde', '\xb9', '\xe6', '\xb9', '\xe6', '\xb9', '\xe6', '\xb9', '\xe6', '\xda', '\xee', '\xda', '\xee', '\xfa', '\xe6', '\xba', '\xde', 'x', '\xd6', 'W', '\xd6', '7', '\xd6', '7']
BlackJack

@Pf@nne: Dann war `FileData` aber auch nicht wie im Betreff vom dem Thema angedeutet ein `bytearray`. Lösung: Es zu einem machen, oder die ”Zeichen” mit der `ord()`-Funktion umwandeln.
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

OK, anders gefragt,

wie bekomme ich die einzelnen Bytes eines Files in eine Liste?

Code: Alles auswählen

with open("75x108.bin", 'rb') as f:
	f.read(0xFFF)
	print list(f)
Da kommen auch "nur" Strings raus......
Jedes Zeichen mit Ord() würde gehen, es muss doch aber auch einen "direkten" weg geben.
BlackJack

@Pf@nne: Offensichtlich will die Funktion eine Liste mit `int`-Objekten haben. Also muss man eine Liste mit `int`-Objekten erstellen. Was sollte da direkter sein als die Bytewerte mit `ord()` in die entsprechenden `int`-Objekte umzuwandeln? Ist ja auch nicht wirklich aufwändig das mit `map()` auf die Zeichenkette anzuwenden.
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

Was sollte da direkter sein als die Bytewerte mit `ord()` in die entsprechenden `int`-Objekte umzuwandeln?
Ich hätte jetzt gesagt, dass die Bytewerte auch als solche ausgelesen werden.
Ein Byte liegt doch im File in der Form BIN[1010_1010] = HEX[AA] = DEC[170] vor, die Zeichenfolge "¬" bzw "\xaa" ist dch schon durch eine Routine gelaufen (Prüfung auf darstellbaren ASCII-Wert).
Ist ja auch nicht wirklich aufwändig das mit `map()` auf die Zeichenkette anzuwenden.
Ich mache es jetzt so:

Code: Alles auswählen

	DataRead = f.read(0xFFF)
	print map(ord, list(DataRead))
Danke für die Unterstützung....
Gruß
Pf@nne
BlackJack

@Pf@nne: Die Methode will ja offenbar unbedingt eine Liste mit `int`-Objekten haben, also muss man ihr auch genau das geben. Und *das* wird ja nicht eingelesen, sondern eine Bytekette als `str`-Datentyp. Die Prüfung auf darstellbare ASCII-Zeichen passiert nur bei der Ausgabe der Liste mit den Zeichenketten, eigentlich Byteketten, mit jeweils einem Zeichen, eigenlich Byte.

Die `list()`-Aufruf ist ein unnötiger Zwischenschritt.
Benutzeravatar
darktrym
User
Beiträge: 785
Registriert: Freitag 24. April 2009, 09:26

Könnte man sicher schöner mit struct.unpack lösen.

Code: Alles auswählen

 DataRead = struct.unpack("4096B", f.read(4096))
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

OK,
hab ich einigermaßen verstanden... :D

Code: Alles auswählen

with open("75x108.bin", 'rb') as f:
	FileSize = os.path.getsize("75x108.bin")
	DataBuffer=[]
	while (FileSize > 0):
		if FileSize > 0xFFF:
			DataBuffer.append(f.read(0xFFF))
			FileSize = FileSize - 0xFFF
		else:
			DataBuffer.append(f.read(FileSize))
			FileSize = 0
for i in range(0, len(DataBuffer)):
	print "SPI_Data",i
	print map(ord, DataBuffer[i])
        #Write SPI_int_List here.......
oder kann man das noch einfacher (schneller) gestalten, je schneller das lesen und Bereitstellen der 4k-Blöcke läuft,
desto schneller wird mein Bild aufgebaut......

Daher wäre eine Optimierung von Vorteil....


Gruß
Pf@nne
BlackJack

@darktrym: In wie weit „schöner”? Bei ``map(ord, data)`` vs. ``list(struct.unpack('{0}b'.format(len(data)), data))`` oder ``list(struct.unpack('b' * len(data), data))`` gewinnt für mich die `map()`-Lösung den Schönheitswettbewerb.

@Pf@nne: Das mit `FileSize` ist unnötig. Einfach so lange 0xfff grosse Blöcke lesen bis die leere Zeichenkette als Abbruchbedingung kommt.

Die ``for``-Schleife über einen Index ist in Python ein „anti pattern”, Du kannst doch *direkt* über die Elemente iterieren. Falls man *zusätzlich* noch einen Index braucht, gibt es die `enumerate()`-Funktion.

Ich würde aber direkt einen Iterator über die Datenblöcke basteln und die gar nicht erst in eine Liste stecken. Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python
from functools import partial


def main():
    with open('75x108.bin', 'rb') as image_file:
        for data in iter(partial(image_file.read, 0xfff), ''):
            print map(ord, data)


if __name__ == '__main__':
    main()
Benutzeravatar
darktrym
User
Beiträge: 785
Registriert: Freitag 24. April 2009, 09:26

Spät. wenn du den gleichen Ausdruck unter Python3 ausführst bekommst du ein Problem weil dann ord eine Exception auslöst wird.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: Und? Hier geht es um Python 2, erkennbar an der ``print``-Anweisung im Quelltext vom OP. Und unter Python 3 bekommt man von dem `read()` ein `bytes`-Objekt wo man einfach ``list(data)`` aufruft. Da wäre etwas mit `struct` noch umständlicher im Vergleich.
Pf@nne
User
Beiträge: 43
Registriert: Donnerstag 18. April 2013, 16:50

Hi,

der Vorschlag von BlackJack läuft einwandfrei...... :D

Code: Alles auswählen

	from functools import partial
	with open('75x108.bin', 'rb') as image_file:
		WriteCMD(0x02)
		GPIO.output(8, False)
		spi.writebytes([0x00]) #WriteData Byte
		image_file.seek(40)     #HeaderOffset 	
		for data in iter(partial(image_file.read, 0xfff), ''):
			spi.writebytes(map(ord, data))
		GPIO.output(8, True)		
Vielen Dank......
Benutzeravatar
darktrym
User
Beiträge: 785
Registriert: Freitag 24. April 2009, 09:26

BlackJack hat geschrieben:@darktrym: Und? Hier geht es um Python 2, erkennbar an der ``print``-Anweisung im Quelltext vom OP. Und unter Python 3 bekommt man von dem `read()` ein `bytes`-Objekt wo man einfach ``list(data)`` aufruft. Da wäre etwas mit `struct` noch umständlicher im Vergleich.
Da hier Raspberry auf einem Linux läuft mit einen in die Jahre gekommenen Python Version, willst du 2014 immer noch Lösungen propagieren die nur auf diese laufen? Umständlicher wäre es ein zweites Mal den gleichen Code anzurühren nur weil man heute zu faul war daran zu denken.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: Du würdest dann also lieber diesen `struct`-Unsinn machen weil das auf beiden Versionen umständlich ist, mit der Begründung das wäre ”schöner”? Ich bin weder zu faul an eine Python-Version zu denken die sich *immer noch nicht* durchgesetzt hat, noch das umzuschreiben, sollte es doch keine Totgeburt sein. ;-) Oh, und wenn man eine Version schreiben möchte die unter beiden Versionen läuft, gibt es eine offensichtliche Lösung ohne `struct` die schöner, weil weniger umständlich ist. Die hatte ich auch schon angesprochen.
Antworten