Textdatei wird nicht komplett eingelesen

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
PUew
User
Beiträge: 5
Registriert: Dienstag 19. Juni 2012, 11:14

Guten Tag,

ich sitze jetzt schon einige Stunden an einem Problem und komme einfach nicht weiter.
Wobei ich gleich dazu sagen muss, dass ich gerade erst angefangen habe Python zu lernen.

Ich möchte eine Textdatei (.log) einlesen und bestimmte Teile davon auswerten.

Das einlesen mache ich wie folgt:

Code: Alles auswählen

fobj = open(DateiPfad, "r")
            DateiInhalt = fobj.read()
            fobj.close()
Als Coding habe ich ganz am Anfang folgendes stehen:

Code: Alles auswählen

#!/usr/bin/env python
# encoding: utf-8
# -*- coding: utf-8 -*-
Die Auswertung des ganzen funktioniert eigentlich.
Allerdings habe ich das Problem, dass manche Dateien nur zum Teil eingelesen werden.

Die log Dateien die ich einlesen will, sehen immer z.B. so aus:

Code: Alles auswählen

)  @)  1   g   ô   @  …    I    È    W  ¦  ï    G     Þ  !  T  Õ    R  „  Ì    S  ¤  Ñ  '  k  º  ö  *	  n	  À	  í	  n
  ³
  ö
  5    ©  û  D  m  ª   
  w
  ½
  õ
  K  ›  ß  !  ¢  å  /  _  —    Ab hier kommt normaler Test der Ausgewertet werden soll.
Also am Anfang kommen irgendwelche seltsamen Zeichen, und danach kommt der Text.

Jetzt habe ich das Problem, dass bei manchen Dateien nur ein paar von Anfangszeichen eingelesen werden, und der eigentlich benötigte Text wird überhaupt nicht mehr eingelesen.

Ich denke mal das liegt daran, dass irgendwann ein Zeichen kommt, dass Python als Dateiende interpretiert.

Wie gesagt, ich habe nicht viel Erfahrung mit Python. Und habe jetzt schon alles mögliche ausprobiert. Allerdings ohne Erfolg.
Ich habe z.B:

Code: Alles auswählen

fobj = codecs.open(DateiPfad, 'r', 'utf8')
ausprobiert, aber entweder die Datei wird weiterhin nur halb ausgelesen, oder ich bekomme irgendwo folgenden Fehler:

Code: Alles auswählen

python UnicodeDecodeError: 'utf8' codec can't decode byte...
Ich hab da jetzt ewig gegoogelt, aber bis jetzt leider keine Lösung gefunden. :(

Ich hoffe hier kann mir jemand helfen. Ich komme da irgendwie nicht weiter.


Ach ja, wenn die Datei komplett eingelesen wurde, dann werte ich sie mit

Code: Alles auswählen

DateiInhaltListe = DateiInhalt.split("::")
for Zeile in DateiInhaltListe:
...
weiter aus. (Falls das wichtig ist.)

Im Prinzip werden ca. 80% der log Dateien richtig eingelesen.
Ich würde mir aber wünschen, dass alle verarbeitet werden.^^


Vielen Dank schon mal.
PUew
User
Beiträge: 5
Registriert: Dienstag 19. Juni 2012, 11:14

Ich habe von so einer log Datei mal einen screenshot gemacht, da das hier "nicht richtig" dargestellt wird.

Bild

P.S.: Ich habe auch schon utf-32 und uft-16 ausprobiert, aber das hatte auch nicht funktioniert.
(Die genaue Fehlermeldung habe ich jetzt leider nicht mehr.)

P.P.S.: Ich benutze Python 2.7
deets

Da ist gleich soviel quer...

Zuerstmal zum Encoding-Cookie: das hat *NICHTS* mit einzulesenden Daten zu tun, sondern bezieht sich *aussschlieslich* auf im Quelltext vorhandene Unicode-String-Literale (bei Python 2.x die mit dem u"" voran)

Und dein eigentliches Problem wirst du auch so nicht geloest bekommen. Wenn du nicht ein *bisschen* mehr weisst ueber die Daten (zb immer wieder ein bestimmtes Token wie dieses 0064: ), dann kannst du da nur heuristisch rangehen. Einfach wild mit encodings rumspielen bringt gar nix, weil die Binaerdaten drumrum diesen nunmal nicht gehorchen. Du musst also erstmal rausfinden, wo die Text-Grenzen sind. Und dann die Texte *darin* dekodieren (wenn's denn Not tut..)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ergänzend zu deets: Sofern es sich um ein Gemisch von binären und textuellen Inhalten handelt, musst Du die Datei erst einmal als Binärdatei öffnen und nicht als Textdatei. Dann kannst Du den / die irrelevanten Teile überspringen (`file.seek`) und die Textfragmente auslesen und sinnvoller Weise in Unicode wandeln (=dekodieren) - das passende Encoding der Texte musst Du dafür allerdings wissen.

Iirc hatten wir mal einen Fall hier, bei dem es sich genau die von mir angenommene Situation handelte. Da sollte es auch Codesnippets dazu geben... evtl. hilft da die SuFu.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
PUew
User
Beiträge: 5
Registriert: Dienstag 19. Juni 2012, 11:14

deets hat geschrieben: Du musst also erstmal rausfinden, wo die Text-Grenzen sind
Also wenn ich mir die Dateien mit einem Hex Editor anschaue, dann fängt der Text immer ca. bei FA (also an Position 250) an.

Aber ich habe ja das Problem, dass manche Dateien nur zum Teil eingelesen werden.
Also bei manchen werden nur ein paar von diesen "Sonderzeichen" eingelesen, und mehr nicht.
Ich bekomme dabei auch keine Fehlermeldung oder so.


Hyperion hat geschrieben: die Datei erst einmal als Binärdatei öffnen und nicht als Textdatei. Dann kannst Du den / die irrelevanten Teile überspringen (`file.seek`) und die Textfragmente auslesen
Okay. Danke. Dann such ich jetzt erstmal wie man die Datei binär einlesen kann.


P.S.: Über die Suche hier hatte ich leider nichts gefunden.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

PUew hat geschrieben: Okay. Danke. Dann such ich jetzt erstmal wie man die Datei binär einlesen kann.

P.S.: Über die Suche hier hatte ich leider nichts gefunden.
Ich habe auch nicht gesagt, dass Du hier im Forum nach Grundlagen suchen sollst, sondern ggf. nach dem Thread, den ich im Kopf hatte. Ich gebe aber zu, dass ich den auch nicht mehr finde...

Wie man Dateien binär öffnet, steht u.a. in der offiziellen Doku.

Mal so als Service für Dich:

Code: Alles auswählen

with open(filename, "rb") as f:
    f.seek(offset)
    data = f.read(text_length)

text = data.decode(encoding)
An `offset` muss die Anzahl an Bytes gebunden sein, die Du überspringen willst. Danach kannst Du entweder alles lesen (`text_length` weglassen), oder eben damit die Länge an Bytes angeben, die Dich interessieren.

Anschließend kannst Du diesen Byte-String noch in einen Unicode-String wandeln, sofern Du das brauchst - ich weiß ja nicht, was Du mit den Daten noch vor hast; idR. ist das aber sinnvoll diese Wandlung durchzuführen, da die meisten Python-Module intern mit Unicode arbeiten und solchen als Parameter auch erwarten.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
PUew
User
Beiträge: 5
Registriert: Dienstag 19. Juni 2012, 11:14

Vielen Dank. Es sieht so aus, als würde es funktionieren. :D

Die Lösung steht hier ja eigentlich schon, aber ich schreibe es trotzdem nochmal.

Mit

Code: Alles auswählen

        fobj = open(DateiPfad, "rb")
        fobj.seek(250,0)
        DateiInhalt = fobj.read()
        fobj.close()
        print DateiInhalt
wird die Datei erst ab "Stelle" 250 eingelesen.
Und das ganze dann als str in DateiInhalt gespeichert.

Im Endeffekt musste man die Datei anstatt "r" mit "rb" einlesen.
Und wegen diesem einen Buchstaben sitze ich hier mehrere Stunden. :roll:

Vielen Dank.

@Hyperion: Danke, da haben wir wohl gerade gleichzeitig geschrieben.
Vielen Dank. :D
Zuletzt geändert von PUew am Dienstag 19. Juni 2012, 12:44, insgesamt 2-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Bitte übernimm das Öffnen von Dateien mittels des `with open() as handler`-Idioms, wie ich es benutzt habe. Damit ist sichergestellt, dass die Datei auf jeden Fall (auch bei Fehlern!) geschlossen wird; ein explizites `file.close` ist zudem nicht mehr notwendig - was bei Dir leider eh bisher fehlte :-P

Wozu Du den optionalen zweiten Parameter (whence) bei `file.seek` angibst, weißt Du sicher selber nicht, oder? ;-) Nötig ist er hier nicht, da der default bereits 0 (=os.SEEK_SET) ist.

Evtl. solltest Du Dir mal die Links in meiner Signatur durchlesen; Du hast im Moment einen kodierten String, also einen Byte-String. Wie ich schon schrieb, kann das je nach Anwendungsfall im Laufe des Programms Probleme verursachen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
PUew
User
Beiträge: 5
Registriert: Dienstag 19. Juni 2012, 11:14

Hyperion hat geschrieben:Bitte übernimm das Öffnen von Dateien mittels des `with open() as handler`-Idioms, wie ich es benutzt habe. Damit ist sichergestellt, dass die Datei auf jeden Fall (auch bei Fehlern!) geschlossen wird; ein explizites `file.close` ist zudem nicht mehr notwendig - was bei Dir leider eh bisher fehlte :-P
Ok, werde ich machen.
Wobei ich in meinem Programm schon ein fobj.close() habe. Hab das nur vergessen hier her zu kopieren.

Aber das Problem dass die Datei nicht geschlossen wird wenn es einen Fehler gibt hatte ich auch schon mal.
Hatte das aber nicht weiter beachtet.

Werde das aber auf jeden Fall noch umsetzen.


Hyperion hat geschrieben:Wozu Du den optionalen zweiten Parameter (whence) bei `file.seek` angibst, weißt Du sicher selber nicht, oder? ;-) Nötig ist er hier nicht, da der default bereits 0 (=os.SEEK_SET) ist.
Doch, hatte ich gegoogelt.^^
0 war von Dateianfang aus, 2 von Dateiende, und 1 ist relativ zur aktuellen Position.^^


Hyperion hat geschrieben: Evtl. solltest Du Dir mal die Links in meiner Signatur durchlesen; Du hast im Moment einen kodierten String, also einen Byte-String. Wie ich schon schrieb, kann das je nach Anwendungsfall im Laufe des Programms Probleme verursachen.
Ok.
Ich denke es gibt im meinem Programm sehr viele Sachen, die "falsch" sind, bzw. besser gelöst werden könnten.
Aber das hier ist mein erstes Python Projekt.
Und ich lerne immer mehr dazu.

Also nochmal Vielen Dank.
Antworten