Das Ergebnis in diesem Fall hat nichts mit dem Windows oder das zu tun Standard-I/O-Implementierung der Microsoft-C-Laufzeit. Wenn Sie dies in Python 2 auf einem Linux-System testen, sehen Sie das gleiche Ergebnis. So funktioniert file.readlines
(2.7.12 Source Link) in Python 2. Siehe Zeile 1717, p = (char *)memchr(buffer+nfilled, '\n', nread)
und dann Zeile 1749, line = PyString_FromStringAndSize(q, p-q)
. Es verbraucht naiv bis zu einem \n
Zeichen, weshalb die eigentliche UTF-16LE \n\x00
Sequenz aufgeteilt wird.
Wenn Sie die Datei mit Python 2s universellem Zeilenumbruchmodus geöffnet haben, z. open('d:/t/hi2.txt', 'U')
, würde die \r\x00
Sequenzen naiv in übersetzt werden. Das Ergebnis von readlines
wäre stattdessen ['\xff\xfeh\x00i\x001\x00\n, \x00\n', '\x00h\x00i\x002\x00']
.
Also Ihre erste Annahme ist richtig. Sie müssen die Codierung kennen oder zumindest nach einer Unicode-BOM (Byte Order Mark) am Anfang der Datei suchen, wie z. B. \xff\xfe
, die UTF-16LE (Little Endian) anzeigt. Zu diesem Zweck empfehle ich das Modul io
in Python 2.7, da es die Newline-Übersetzung korrekt behandelt. codecs.open
, auf der anderen Seite, erfordert Binärmodus auf der umwickelte Datei und Universal-Newline ignoriert Modus:
>>> codecs.open('test.txt', 'U', encoding='utf-16').readlines()
[u'hi1\r\n', u'hi2']
io.open
gibt ein TextIOWrapper
, die Unterstützung für die universellen newlines-in gebaut hat:
>>> io.open('test.txt', encoding='utf-16').readlines()
[u'hi1\n', u'hi2']
In Bezug auf Microsofts CRT, wird standardmäßig ANSI-Textmodus verwendet. Die ANSI-Codepages von Microsoft sind Obermengen von ASCII, sodass die Zeilenumsetzung des CRT für Dateien funktioniert, die mit einer ASCII-kompatiblen Codierung wie UTF-8 codiert sind. Auf der anderen Seite, ANSI-Text-Modus für eine UTF-16 codierte Datei nicht funktioniert, dh es ist nicht das UTF-16 LE BOM (\xff\xfe
) und nicht übersetzt nicht entfernt Zeilenumbrüche:
>>> open('test.txt').read()
'\xff\xfeh\x00i\x001\x00\r\x00\n\x00h\x00i\x002\x00'
So verwendet Standard-E/A-Textmodus für eine UTF-16-kodierte Datei erfordert das nicht standardmäßige ccs
-Flag, z fopen("d:/t/hi2.txt", "rt, ccs=UNICODE")
. Python unterstützt diese Microsoft-Erweiterung für das offene mode
nicht, aber es stellt die niedrigen E/A-Funktionen (POSIX) des CRT im os
Modul zur Verfügung. Während es POSIX-Programmierer überraschen mag, unterstützt die Low-I/O-API von Microsoft auch den Textmodus, einschließlich Unicode. Zum Beispiel:
>>> O_WTEXT = 0x10000
>>> fd = os.open('test.txt', os.O_RDONLY | O_WTEXT)
>>> os.read(fd, 100)
'h\x00i\x001\x00\n\x00h\x00i\x002\x00'
>>> os.close(fd)
Die O_WTEXT
Konstante ist nicht direkt in Windows Python gemacht, weil sie mit diesem Modus einen Dateideskriptor zu öffnen als Python file
mit os.fdopen
nicht sicher ist. Die CRT erwartet, daß alle Puffer mit breiten Zeichen ein Vielfaches der Grße von wchar_t
sind, d. H. Ein Vielfaches von 2. Andernfalls ruft sie den ungültigen Parameterhandler auf, der den Prozeß beendet. Zum Beispiel (mit dem CDB-Debugger):
>>> fd = os.open('test.txt', os.O_RDONLY | O_WTEXT)
>>> os.read(fd, 7)
ntdll!NtTerminateProcess+0x14:
00007ff8`d9cd5664 c3 ret
0:000> k8
Child-SP RetAddr Call Site
00000000`005ef338 00007ff8`d646e219 ntdll!NtTerminateProcess+0x14
00000000`005ef340 00000000`62db5200 KERNELBASE!TerminateProcess+0x29
00000000`005ef370 00000000`62db52d4 MSVCR90!_invoke_watson+0x11c
00000000`005ef960 00000000`62db0cff MSVCR90!_invalid_parameter+0x70
00000000`005ef9a0 00000000`62db0e29 MSVCR90!_read_nolock+0x76b
00000000`005efa40 00000000`1e056e8a MSVCR90!_read+0x10d
00000000`005efaa0 00000000`1e0c3d49 python27!Py_Main+0x12a8a
00000000`005efae0 00000000`1e1146d4 python27!PyCFunction_Call+0x69
Gleiches gilt für _O_UTF8
und _O_UTF16
gilt.
Windows hat kein Konzept von "Textmodus". Sie sprechen über die C-Laufzeit, aber standardmäßig wird der ANSI-Textmodus verwendet, der keine UTF-16-Sequenz "\ r \ x00 \ n \ x00" erkennt. Was Sie tatsächlich sehen, ist die Implementierung der Methode ['file.readlines'] (https://hg.python.org/cpython/file/v2.7.12/Objects/fileobject.c#l1659) in Python 2. Siehe Zeile 1717, 'p = (char *) memchr (Puffer + nfilled, '\ n', nread)' und dann Zeile 1749, 'line = PyString_FromStringAndSize (q, pq)'. Es verbraucht naiv bis zu einem '\ n'-Zeichen, weshalb das eigentliche UTF-16LE' \ n \ x00' geteilt wird. – eryksun
* Windows hat kein Konzept von "Textmodus" * - [fopen() bei MSDN] (https://msdn.microsoft.com/en-us/library/yeby3zcb%28vs.71%29.aspx) - "* Im Textmodus werden Wagenrücklauf-Zeilenvorschub-Kombinationen bei der Eingabe in einzelne Zeilenvorschübe umgesetzt, und Zeilenvorschub-Zeichen werden bei der Ausgabe in Wagenrücklauf-Zeilenvorschub-Kombinationen übersetzt.Wenn eine Unicode-Stream-E/A-Funktion im Textmodus (Standard) ausgeführt wird, Quell- oder Zielstream wird als eine Folge von Multibyte-Zeichen angenommen. * ". Aber es macht Sinn, dass das Unicode-Quad von Python zerschmettert wird, das ist wahrscheinlich meine Antwort. – TessellatingHeckler
Microsofts '_open',' fopen', '_read',' fread' usw. sind alle C-Laufzeitfunktionen. Sie sind nicht von Natur aus Teil von Windows-Datei-I/O, d.h. 'CreateFile',' ReadFile' usw. Die Verwendung von Microsofts CRT ist optional. Sie können eine andere CRT verwenden, die keinen "Textmodus" hat, oder Sie können einfach die Windows-API direkt verwenden. Es kommt vor, dass Windows Python mit MSVC erstellt wird und die CRT-I/O- und Standard-I/O-Laufzeitfunktionen verwendet, um plattformübergreifende Kompatibilität mit POSIX-Betriebssystemen wie Linux und OS X zu ermöglichen. – eryksun