Seite 1 von 1
File schnell 2byte-weise einlesen
Verfasst: Dienstag 30. Mai 2006, 14:09
von tromai
Hallo zusammen,
ich habe eine Frage zum Einlesen von Dateien.
Das Problem ist das folgende:
Ich habe eine recht große Datei, die ich in ein 2d NumPy-Array einlesen möchte. Und zwar sollen immer 2 Zeichen in ein Array-Element geladen werden.
Bisher habe ich das folgendermaßen gemacht:
Code: Alles auswählen
File = file('Filename')
for n in range(900):
for m in range(900):
array[n][m] = File.read(2)
Das klappt wunderbar. Das Problem ist, dass das einfach zu lange für die Anwendung dauert. Kann mir jemand eine schnellere Methode empfehlen das File einzulesen?
Danke schonmal im voraus.
Re: File schnell 2byte-weise einlesen
Verfasst: Dienstag 30. Mai 2006, 16:06
von gerold
tromai hat geschrieben:Bisher habe ich das folgendermaßen gemacht:
Code: Alles auswählen
File = file('Filename')
for n in range(900):
for m in range(900):
array[n][m] = File.read(2)
Hi tromai!
Vielleicht ist das schneller:
Code: Alles auswählen
daten = []
f = file('hallo.bin', "rb")
try:
for paket in iter(lambda: f.read(1024), ""):
zaehler = 0
for zaehler in range(0, len(paket), 2):
try:
daten.append(
(paket[zaehler], paket[zaehler + 1])
)
except:
print "ACHTUNG!!! Anzahl Zeichen -- ungerade!"
finally:
f.close()
print daten
Aber nur vielleicht...
Du musst es natürlich auf dein Array umsetzen. Ich habe noch nie mit Python-Arrays gearbeitet, deshalb habe ich dieses Beispiel einfach als Liste mit Tuppeln umgesetzt.
mfg
Gerold
Re: File schnell 2byte-weise einlesen
Verfasst: Mittwoch 31. Mai 2006, 07:45
von BlackJack
tromai hat geschrieben:Das Problem ist das folgende:
Ich habe eine recht große Datei, die ich in ein 2d NumPy-Array einlesen möchte. Und zwar sollen immer 2 Zeichen in ein Array-Element geladen werden.
Wieso Zeichen in einem NumPy-Array? Die sind doch eher für Zahlen gedacht. Sicher das Du nicht 16-Bit Zahlen da drin haben möchtest?
Bisher habe ich das folgendermaßen gemacht:
Code: Alles auswählen
File = file('Filename')
for n in range(900):
for m in range(900):
array[n][m] = File.read(2)
Das klappt wunderbar. Das Problem ist, dass das einfach zu lange für die Anwendung dauert. Kann mir jemand eine schnellere Methode empfehlen das File einzulesen?
Funktioniert vielleicht etwas in der Richtung:
Code: Alles auswählen
import numpy
array = numpy.fromfile('Filename', dtype='<i2', count=900 * 900)
array = array.reshape(900, 900)
Verfasst: Mittwoch 31. Mai 2006, 09:17
von CM
Hoi,
würde mich wundern, wenn das funktioniert:
1.) count wird auf 810000 gesetzt, was bedeutet, das ebensoviele Zeichen vom gewünschten Typ eingelesen werden. Das muß nicht schlimm sein, limitiert aber künstlich. Besser ist wahrscheinlich der Default von -1 = das ganze File.
2.) wenn "array" ein numpy-array ist, ist ein Variablenname "array" ungünstig.
Davon abgesehen finde ich den Vorschlag aber gut.
Im Übrigen tendiere ich dazu Daten in Listen einzulesen und für den weiteren Gebrauch in arrays umzuwandeln - das ist zwar aufwendiger, aber meist übersichtlicher (finde ich). Der Overhead ist meist vernachlässigbar. Speichern mache ich dann über
picklen wie im link beschrieben.
Gruß,
Christian
PS
Sollten die 2 Byte mit einem 16bit Bild korrespondieren gibt es die Möglichkeit in Kombination mit scipy.misc.fromimage zu konvertieren.
Verfasst: Mittwoch 31. Mai 2006, 15:12
von tromai
Ok, auf jeden Fall mal danke.
Ich werde mal die unterschiedlichen Varianten ausprobieren und dann berichten. Kann allerdings ein paar Tage dauern.
Verfasst: Donnerstag 1. Juni 2006, 09:36
von tromai
So, jetzt habe ich doch noch einmal ein paar Fragen:
1. Habe ich das richtig verstanden, dass
dtype='<i2' die Anzahl der Zeichen festlegt?
2. Ich habe bisher keine gut Docu zu dem Befehl numpy.fromfile gefunden. Vielleicht kennt ja jemand einen Link.
3. Gibt es eine Möglichkeit einen Offset anzugeben? Für das File um das es ursprünglich wäre das nicht nötig. Allerdings ist nun auch noch ein zweites File mit einem Header dazugekommen.
Danke schonmal im Voraus.
[Edit: Frage 1 und 3 konnte ich mir Mittlerweile selbst beantworten. Allerdings ist jetzt noch eine Frage 4 dazu gekommen:
Un zwar erhalte, ich wenn ich ein Textfile mir dem Inhalt
mir dem Befehl:
Code: Alles auswählen
arrh = numpy.fromfile(radFile, dtype = '<i2', count = 2)
einlese, die Werte
Ok, wie das zu Stande kommt ist klar. Der erste Wert berechnet sich folgendermaßen:
ASCII-Code für 1 ist 49
ASCII-Code für 2 ist 50
49+50*256=12849
Es wäre also kein Problem das ganze zurückzurechnen. Allerdings würde das wiederum das schnelle Einlesen zunichte machen. Gibt es eine Funktion, die mir das direkt für einen kompletten array umwandelt? Bzw. kann ich das ganze auch gleich als Zahl oder 1 zu 1 als String einlesen, so dass ich dann in meinem Array 12 und 34 stehen habe?
Verfasst: Donnerstag 1. Juni 2006, 12:57
von CM
Hoi,
1.) Nein, hast Du nicht: dtype legt den "minimalen" Datentyp Deines Arrays fest.
Beispiel:
Code: Alles auswählen
a = arange(10,dtype='<i2') #array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int16)
b = arange(10) #array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
c = arange(10,dtype='i2') #array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int16)
Eine Erklärung magst Du
hier finden.
2.) Einen Link kenne ich nicht, aber ein
Beispiel.
Und den Docstring:
Code: Alles auswählen
>>> print numpy.fromfile.__doc__
fromfile(file=, dtype=int, count=-1, sep='')
Return an array of the given data type from a
(text or binary) file. The file argument can be an open file
or a string with the name of a file to read from. If
count==-1, then the entire file is read, otherwise count is
the number of items of the given type read in. If sep is ''
then read a binary file, otherwise it gives the separator
between elements in a text file.
WARNING: This function should be used sparingly, as it is not
a platform-independent method of persistence. But it can be
useful to read in simply-formatted or binary data quickly.
3.) Nicht implizit. Aber Du kannst Deine eigene Funktion schreiben, die den Header überspring. (fromfile akzeptiert als input ja nicht nur einen Dateinamen, sondern auch das geöffnete File.)
Außerdem: Kennst Du
PyTables. Das baucht zwar z. Zt. noch auf numarray auf, wird aber in absehbarer Zeit auf numpy umstellen und die Konvertierung von numarray zu numpy arrays ist ja leicht.
Funktioniert denn jetzt das Einlesen Deines ursprünglichen Files?
Gruß,
Christian
Verfasst: Donnerstag 1. Juni 2006, 13:19
von tromai
*g*
Da haben wir wohl gleichzeitig geschrieben. Frage 1 war dann doch noch nicht geklärt. Aber jetzt habe ich es verstanden.
THX
Verfasst: Donnerstag 1. Juni 2006, 13:26
von tromai
Ok, die letzte offene Frage hat sich auch geklärt über dtype='S2' lässt sich ein string der länge 2 einlesen.
Verfasst: Donnerstag 8. Juni 2006, 09:28
von tromai
Jetzt ist doch noch ein Problem aufgetreten.
Ich lese das File über diesen Befehl ein
Code: Alles auswählen
arrh = numpy.fromfile(radFile, dtype = 'S2', count = 900*900)
Mein Problem ist jetzt, dass das File gezippt ist.
Über gzip.open lässt sich das File ja ohne Probleme öffnen:
Allerdings bekomme ich da bei dem Befehl "numpy.fromfile" Probleme. Das Script sieht folgendermaßen aus:
Code: Alles auswählen
radFile = gzip.open('blabla.gz')
readHeader(radFile)
arrh = numpy.fromfile(radFile, dtype = 'S2', count = 900*900)
Und gibt folgenden Fehler aus:
Code: Alles auswählen
Traceback (most recent call last):
File "funcV5.py", line 87, in radIn
arrh = numpy.fromfile(radFile, dtype = 'S2', count = 900*900)
IOError: first argument must be an open file
Allerdings hatte ich gzip.open so verstanden, dass es das File als Objekt importiert und somit sollte es doch keinen derartigen Fehler geben. Aber scheinbar liege ich da falsch
Vielleicht hat ja jemand eine Lösung für das Problem.
Verfasst: Freitag 9. Juni 2006, 06:45
von BlackJack
Frag am besten auf der numpy-Mailingliste nach, warum die das nicht als Datei-Objekt akzeptieren.
Verfasst: Montag 12. Juni 2006, 08:55
von tromai
Ok, werde ich mal machen. Ich habe mittlerweile von anderer Stelle Support bekommen und es folgendermaßen gelöst:
Code: Alles auswählen
gzstream = open('file.gz', 'rb')
gz = GzipFile(fileobj=gzstream, mode='rb')
streamBuf = StringIO()
streamBuf.write(gz.read())
arrh = numpy.fromstring(streamBuf.getvalue(), dtype = 'S2', count = 900*900)
Ich habe auch gleich die nächste Frage:
Ich verwende ja dtype='S2'.
Welchen dtype müsste mann denn verwenden, wenn man einfach 2 Byte einlesen will? Das Problem ist, dass in dem File des öfteren der Wert NULL vorkommt und in dem String dann natürlich nichts drin steht. Wie kann ich das Problem umgehen? Wenn ich das File mit read(2) auslese, dann gibt es keine Probleme.
Vielleicht weiß ja auch jemand wo ich eine Liste aller dtypes herbekomme.
Verfasst: Montag 12. Juni 2006, 22:33
von BlackJack
tromai hat geschrieben:Ok, werde ich mal machen. Ich habe mittlerweile von anderer Stelle Support bekommen und es folgendermaßen gelöst:
Code: Alles auswählen
gzstream = open('file.gz', 'rb')
gz = GzipFile(fileobj=gzstream, mode='rb')
streamBuf = StringIO()
streamBuf.write(gz.read())
arrh = numpy.fromstring(streamBuf.getvalue(), dtype = 'S2', count = 900*900)
Das kannst Du auch einfacher haben. `gz.read()` liefert schon eine Zeichenkette, die muss man nicht nochmal in ein StringIO Objekt verpacken und dann wieder rausholen.
Code: Alles auswählen
gzstream = open('file.gz', 'rb')
gz = GzipFile(fileobj=gzstream, mode='rb')
arrh = numpy.fromstring(gz.read(), dtype = 'S2', count = 900*900)
Ich habe auch gleich die nächste Frage:
Ich verwende ja dtype='S2'.
Welchen dtype müsste mann denn verwenden, wenn man einfach 2 Byte einlesen will? Das Problem ist, dass in dem File des öfteren der Wert NULL vorkommt und in dem String dann natürlich nichts drin steht. Wie kann ich das Problem umgehen? Wenn ich das File mit read(2) auslese, dann gibt es keine Probleme.
Warum möchtest Du überhaupt Zeichenketten in einem Numpy-Array haben? Was machst Du mit den Daten nachdem sie eingelesen wurden?
Verfasst: Dienstag 13. Juni 2006, 12:52
von tromai
Der Teil des Codes stammt nicht von mir. Was genau das Problem war, wenn man nur gz.read() gemacht hat kann ich dir nicht sagen. Auf jeden Fall gab es dann Probleme mir fromstring(). So geht es jetzt. Aber ich werde nochmal ausprobieren.
Das Einlesen als string stammte noch aus aus einem früheren Entwicklungsstadium. Ist aber natürlich völlig überflüssig. Danke für den Hinweis. Das hat nämlich jetzt mein Problem komplett gelöst. Hätte ich auch früher drauf kommen können
Code: Alles auswählen
gz = GzipFile(fileobj=gzstream, mode='rb')
streamBuf = StringIO()
streamBuf.write(gz.read())
radFile = streamBuf.getvalue()
arrh = numpy.fromstring(radFile, dtype = numpy.uint16, count = 900*900)