Byteweise einlesen

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
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

Mit input.read(N)
kann ich eine Datei byteweise einlesen. Er liest mir dann fuer N N-Bytes ein.
Wenn ich N = 20 setze, dann lese ich die ersten 20 Bytes ein. Was ist, wenn ich die naechsten Bytes einlesen moechte 20 bis 40 meinentwegen.
Geht so etwas auch?
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

währe dann eventuell so etwas:

Code: Alles auswählen

fileobj = open('test.txt', 'rb')
ges = ''
while True:
    data = fileobj.read(20)
    if not data:
        break
    ges += data
Du lässt das File-Objekt einfach offen. Dadurch ließt er automatisch die nächsten 20 Bytes ein.

entnommen aus dem Beispiel:
[wiki]MD5 sum bilden[/wiki]

MfG EnTeQuAk

€dit: Man sollte die Datei im Binärmodus öffnen.
Danke BlackJack!
Zuletzt geändert von EnTeQuAk am Montag 2. Juli 2007, 10:51, insgesamt 1-mal geändert.
BlackJack

Man kann auch `iter()` mit zwei Argumenten benutzen:

Code: Alles auswählen

In [5]: f = open('test.dat', 'rb')

In [6]: for data in iter(lambda: f.read(20), ''):
   ...:     print len(data), repr(data)
   ...:
20 "((S'name'\np0\nS'beruf"
20 "'\np1\ntp2\n(lp3\n(I0\n(S"
20 "'Eric'\np4\nS'Viking'\n"
17 'p5\ntp6\ntp7\natp8\n.'
Auf jeden Fall sollte man die Datei im Binärmodus öffnen, wenn man mit Bytes operiert.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

Wenn ich die Variante 1 (EnTeQuAk) waehlen moechte, kann ich dann so etwas noch machen?

Code: Alles auswählen

inp1 = open('out.tab','rb')
ges = ''
while True:
    data = inp1.read(53980409)
    if not data:
        break
    ges += data

    neg = set()
    for line in data:
...
Funktioniert for line in data noch, oder muss ich die Binaerdatei dann wieder in einen String umwandeln?
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

silky vanilla hat geschrieben: Funktioniert for line in data noch, oder muss ich die Binaerdatei dann wieder in einen String umwandeln?
Entweder hast du dich verschrieben, dein Code stimmt so nicht oder die frage hat sich im Enddefekt erledigt.


Wenn wir mal von deinem Code ausgehen. Du hast in der Variablen 'data' dann die 53980409 Bytes drinne. Dann willst du zeile für zeile durch diese Anzahl an Bytes durchgehen?

Was kommt nach dieser 'for' Schleife?

Ob du die Datei nun noch umwandeln musst oder nicht, kann ich aus dem FF nicht sagen. Probier es einfach mal aus :)

Code: Alles auswählen

f = open('test.txt', 'r')
for line in f:
    print line
f.close()
f = open('test.txt', 'rb')
for line in f:
    print line
f.close()
Ich meine; dafür haben wir die Wunderwaffe Interpreter :)


MFG EnTeQuAk
BlackJack

@silky vanilla: Das sieht sehr wirr aus. Wie kommt die Zahl bei `read()` zustande? Kannst Du da sicher sein, dass nicht die letzte Zeile "mittendrin" abgeschnitten wird? Sind das nun Textzeilen oder Binärdaten?

``for line in data`` funktioniert so natürlich nicht, da `data` eine grosse Zeichenkette bzw. Bytekette ist und an `line` bei jedem Schleifendurchlauf jeder Buchstaben bzw. jedes Byte einzeln gebunden würde. Dazu müsste man die Daten mit der `splitlines()`-Methode in eine Liste von einzelnen Zeilen aufsplitten. Also ca. 51 MiB grosse Brocken einlesen, die dann aufsplitten, wobei zumindest zeitweise nochmal 51 MiB belegt werden müssen!?

Oh und in `ges` sammelst Du dann, auf ineffiziente Weise, nochmal alle Daten aus der Datei. Wozu?

Verrate doch mal was Du überhaupt machen oder erreichen willst.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

ok. Ich habe eine Datei, die 360 MB gross ist.
Was ich mache ist folgendes:

Code: Alles auswählen

 
inp = open('   ','r')
for line in data:
        edge = line.split()
        if len(edge) < 2: continue
        gene1, gene2 = edge[:2]
        neg.add((gene1, gene2))
        neg.add((gene2, gene1))
...usw.
Wenn ich das mit der kompletten Datei mache, reicht der Speicher nicht aus, also wollte ich sie in Teilstuecken bearbeiten.
Es gibt da ja auch noch die Variante x.readlines(), aber da weiss ich auch nicht so richtig wie ich das mit der for Schleife dann mache.
BlackJack

Es ist also eine Textdatei. Dann ist das einlesen von Stücken bei denen Du die Bytegrösse vorgibst, keine gute Idee weil dabei Zeilen "kaputt gehen" können.

Nachdem was Du hier bisher gezeigt hast, solltest Du am besten erst einmal die einzelnen Schritte der Verarbeitung in Funktionen stecken. Dann ist schon einmal sichergestellt, dass temporäre, lokale Datenstrukturen nach der Abarbeitung der Funktion wieder freigegeben werden können.

Falls das nicht ausreicht, könnte man eine Generatorfunktion schreiben, die Iteratoren über Blöcke von Zeilen liefert:

Code: Alles auswählen

from itertools import groupby, imap
from operator import itemgetter


def lineblocks(lines, count):
    def stamp_lines(lines):
        block_nr = -1
        for i, line in enumerate(lines):
            if i % count == 0:
                block_nr += 1
            yield (block_nr, line)
    
    for i, lines in groupby(stamp_lines(lines), itemgetter(0)):
        yield (i, imap(itemgetter(1), lines))


def main():
    lines = open('test.py', 'r')
    for i, lineblock in lineblocks(lines, 10):
        print 'line block #%d' % i
        for line in lineblock:
            print '   >', line,
    lines.close()
Kannst Du überhaupt mit Teilstücken arbeiten? Sind die Daten in den Blöcken denn unabhängig voneinander?

Letztendlich musst Du vielleicht über eine Datenbank nachdenken, wenn die Datenmenge den Hauptspeicher sprengt.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

@BlackJack: Ja, es ist eine Textdatei, sie enthaelt zwei Spalten, die durch Tabulator getrennt sind. In den Spalten steht eine Zeichenkette.
Mit Teilstuecken kann ich arbeiten, die Daten sind in dieser Hinsicht unabhaengig voneinander.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

ok, ich glaub mit der variante, wie vorgeschlagen, komme ich nicht richtig zurecht.

gibt es etwas, wo ich eine Datei einfach teilen kann?

Meinetwegen teile ich die Datei in vier Teile, dann sind die Dateigroessen so gross, dass der Speicher ausreichend ist.
BlackJack

Du müsstest bei der `lineblocks()`-Funktion nur `count` so wählen, dass es ¼ der Zeilenanzahl der Datei ist.
silky vanilla
User
Beiträge: 51
Registriert: Donnerstag 3. Mai 2007, 09:46

ok, nochmal anders formuliert.

Ich moechte es mir nicht sonderlich schwer machen.

Es ist zwar eine Textdatei, aber ich habe diese jetzt binaer geteilt. Das ging deshalb so einfach,weil ich weiss was in der letzten Spalte der ersten Haelfte der Datei stehen muss, so hab ich nachgeschaut und die Bytes die noch fehlen dazuaddiert.

So enthaelt die erste Haelfte der Datei 188931434 Bytes.
Diese Bytes habe ich einfach wieder in einem Dateiformat ausgegeben.

Mein Skript habe ich dann mit dieser neuen "halben" Datei laufen lassen, das funktioniert auch super.

Nun muss ich lediglich die zweite Haelfte (sprich Byte188931434+1 bis 377862863(Gesamtbytezahl)) in einem Dateiformat ausgeben, damit ich diese Datei ebenfalls durch mein Skript laufen lassen kann.

Bloss wie komme ich an die Bytes heran? Kann mir da jemand weiter helfen?
Antworten