2016-05-10 7 views
3

Aufruf tell() beim Lesen einer GBK-codierten Datei von mir verursacht den nächsten Anruf an readline(), um eine UnicodeDecodeError zu erhöhen. Wenn ich jedoch tell() nicht aufrufen, wird dieser Fehler nicht ausgelöst.Warum beeinflusst file.tell() die Codierung?

C: \ tmp> hexdump badtell.txt

000000: 61 20 6B 0D 0A D2 BB B0-E3      a k...... 

C: \ tmp> type test.py

with open(r'c:\tmp\badtell.txt', "r", encoding='gbk') as f: 
    while True: 
     pos = f.tell() 
     line = f.readline(); 
     if not line: break 
     print(line) 

C: \ tmp> Python test.py

a k 

Traceback (most recent call last): 
    File "test.py", line 4, in <module> 
    line = f.readline(); 
UnicodeDecodeError: 'gbk' codec can't decode byte 0xd2 in position 0: incomplete multibyte sequence 

Wenn ich die f.tell() Anweisung lösche, dekodiert es erfolgreich. Warum? Ich versuchte Python3.4/3.5 x64 auf Win7/Win10, es ist alles gleich.

Irgendwelche Idee? Soll ich einen Fehler melden?

Ich habe eine große Textdatei, und ich möchte wirklich Dateipositionsbereiche dieses großen Textes erhalten, gibt es einen Workaround?

+0

ich einen großen Text hatte Datei, und ich möchte wirklich Dateiposition Bereiche Teile dieses großen Textes zeigen, gibt es eine Umgehung? danke – mfmain

Antwort

1

Ich replizierte dies nur auf Python 3.4 x64 unter Linux. Betrachtet man die Dokumente für TextIOBase, sehe ich nichts, dass tell() verursacht Probleme beim Lesen einer Datei, also vielleicht ist es in der Tat ein Fehler.

b'\xd2'.decode('gbk') 

gibt einen Fehler wie die, die Sie gesehen haben, aber in der Datei ist, dass Byte für Byte BB gefolgt und

b'\xd2\xbb'.decode('gbk') 

ergibt einen Wert gleich '\u4e00', kein Fehler.

Ich habe eine Problemumgehung gefunden, die für die Daten in Ihrer ursprünglichen Frage funktioniert, aber nicht für andere Daten, wie Sie seit dem gefunden haben. Ich wünschte, ich wüsste warum! Ich rief seek() nach jedem tell(), mit dem Wert, den tell() zurückgegeben:

pos = f.tell() 
f.seek(pos) 
line = f.readline() 

Eine Alternative zu f.seek(f.tell()) ist die SEEK_CUR Modus von seek() zu verwenden, um die Position zu geben. Bei einem Offset von 0 entspricht dies dem obigen Code: bewegt sich zur aktuellen Position und erhält diese Position.

pos = f.seek(0, io.SEEK_CUR) 
line = f.readline() 
+0

Großartig! f.seek (0, io.SEEK_CUR) funktioniert für mich auf Python 3.4 x64/win7 – mfmain

+0

Etwas ist wieder seltsam, dieses Mal, suchen Sie die schlechte Sache: – mfmain

+0

C: \ tmp> hexdump-r badtell.txt 5B 74 61 67 5F 75 73 65 72 20 74 61 67 5F 47 65 74 4D 65 73 73 61 67 65 20 74 61 67 5F 6D 65 73 73 61 67 65 5D 0D 0A D3 C3 BB A7 CF FB CF A2 3A 20 57 4D 5F 55 53 45 52 20 7E 20 2E 0D 0A 0D 0A 2F 2F 20 54 0D 0A 2F 2F 20 CD F9 45 44 49 54 CE C4 B1 BE 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A – mfmain

1

OK, ist es eine Abhilfe, Es funktioniert so weit:

with open(r'c:\tmp\badtell.txt', "rb") as f: 
    while True: 
     pos = f.tell() 
     line = f.readline(); 
     if not line: break 
     line = line.decode("gbk").strip('\n') 
     print(line) 

ich gestern hier ein Problem gestellt: http://bugs.python.org/issue26990

noch keine Antwort noch