Те же правила действуют и для текстовых файлов, потому что строки Юникода сохраняются в файлах в виде декодированных байтов. При записи мы можем закодировать строку с применением любой кодировки, совместимой с символами, имеющимися в строке. Однако при чтении необходимо заранее знать кодировку или использовать ту, которая декодирует байты в те же самые символы:
> >> open(‘ldata’, ‘w’, encoding=’latin-1’).write(s) # сохранить в latin-1 5
> >> open(‘udata’, ‘w’, encoding=’utf-8’).write(s) # сохранить в utf-8
5
> >> open(‘ldata’, ‘r’, encoding=’latin-1’).read() # OK: корректное имя
‘ AABaC’
>>> open(‘udata’, ‘r’, encoding=’utf-8’).read()
‘AABaC’
>>> open(‘ldata’, ‘r’).read() # иначе может вернуть ошибку
‘AABaC’
>>> open(‘udata’, ‘r’).read()
UnicodeEncodeError: ‘charmap’ codec can’t encode characters in position 2-3: cha..
>>> open(‘ldata’, ‘r’, encoding=’utf-8’).read()
UnicodeDecodeError: ‘utf8’ codec can’t decode bytes in position 1-2: invalid dat.
>>> open(‘udata’, ‘r’, encoding=’latin-1’).read()
UnicodeEncodeError: ‘charmap’ codec can’t encode character ‘\xc3’ in position 2:.
Напротив, при чтении из файлов в двоичном режиме попытка декодировать данные в строку Юникода не производится. Они благополучно будут прочитаны независимо от того, в каком режиме были записаны эти данные — в текстовом, с автоматическим кодированием строк str (как в предыдущем интерактивном сеансе), или в двоичном, в виде строк bytes, закодированных вручную:
>>> open(‘ldata’, ‘rb’).read()
b’A\xc4B\xe4C’
>>> open(‘udata’, ‘rb’).read()
b’A\xc3\x84B\xc3\xa4C’
> >> open(‘sdata’, ‘wb’).write( s.encode(‘utf-16’) ) # вернет число: 12
> >> open(‘sdata’, ‘rb’).read()
b’\xff\xfeA\x00\xc4\x00B\x00\xe4\x00C\x00’
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011