Kodomo

Пользователь

Файлы. Кодировки. Работа с файлами.

Напоминание

Для понимания материала ОБЯЗАТЕЛЬНО каждый пример пытаться исполнить, понять, почему он работает или не работает, и попробовать в нём что-то поменять, и посмотреть, что получится.

Программирование – это практическая дисциплина, и без успешных попыток что-то сделать руками понимания теории не появляется.

Что такое текстовый файл

С точки зрения операционной системы, и, следовательно, питона, файл – это последовательность байт. (Можно считать, что один байт – это одно число от 0 до 255, то есть если бы у нас был алфавит из 256 букв, то файл из N байт – это N букв этого алфавита).

Общепринято нестрогое и неформальное деление файлов на текстовые и бинарные.

В текстовом файле последовательность байт несёт единственный смысл: последовательность букв текста в человеческом понимании. (В простейшем виде действует соотношение: один байт – одна буква). Т.е. в текстовом файле кроме текста нет ничего. Простейший пример текстового файла – текст, набранный в notepad (он же блокнот) в windows.

В бинарном файле, в зависимости от типа файла (например, картинка JPEG, ролик MKV, документ DOC, архив ZIP) разным байтам придаётся разный смысл: какие-то трактуются как числа, какие-то обозначают яркость канала цвета, какие-то громкость звука. Если бы мы попытались открыть бинарный файл текстовым редактором (например, notepad), то мы увидим непонятную ерунду: потому, что мы те же байты пытаемся интерпретировать с точки зрения другого языка. (Как пытаться расслышать русские слова в китайской речи).

Начиная с этого занятия мы обнаружим, что в питоне гораздо проще общаться с текстовыми файлами.

Понятие кодировки

Кодировка текста – это правила, которые устанавливают, какие байты соответствуют какой букве.

Очень важная кодировка – ASCII. Это одна из довольно старых кодировок, она стандартизована в Америке в 1963 году, и она приписывает 128 различным значениям байта буквы, цифры, и основные знаки пунктуации. В этой кодировке один байт обозначает одну букву, но для некоторых значений байта начертание не определено.

За ней последовало множество кодировок для разных стран: западной Европы, Греции, России, которые заполняли оставшиеся 128 значений каким-нибудь образом так, чтобы запихать туда необходимые символы (буквы с различными диакритическими знаками, греческие буквы, русские буквы, арабская вязь, японская кана и т.п). Из них полезно уметь узнавать хотя бы названия трёх старых кодировок для русского языка:

Во всех этих кодировках байты с числовыми значениями от 0 до 127 совпадают с ASCII, а остальным значениям приписаны русские буквы (притом везде разными, никак друг на друга не похожими способами).

Для языков, которые используют китайские иероглифы, сделать кодировку с отображением один байт = один символ невозможно, поэтому китайцы, японцы и корейцы посочиняли для себя кодировок, где один иероглиф задаётся последовательностью из двух-четырёх байт рядом.

Всего таких кодировок образовалось порядка тысячи. А для того, чтобы иметь возможность между ними конвертировать тексты, нужно (задача по математике – сколько?) перекодировщиков.

Поэтому в конце 80-х годов возник The Unicode Consortium, который стал собирать реестр всех символов, которые возможно представлять в компьютере. Этот реестр стал называться Unicode.

Идея Unicode в том, что для того чтобы сделать универсальный перекодировщик текстов достаточно для каждой буквы сначала её расшифровать согласно таблицы для соответствующей кодировки и определить место этой буквы в реестре Unicode, а затем выдав представление этой буквы во второй кодировке.

Кроме того, The Unicode Consortium определило несколько кодировок, предназначенных для того, чтобы хранить все символы из реестра Unicode:

Два типа строк в питоне

Строки, с которыми мы до сих пор работали в питоне, на самом деле были просто списками байтов. Для кодировки ASCII или других однобайтовых кодировок получается только одна беда – мы будем на экран писать те же байты, что и в тексте программы, а если экран отображает другую кодировку, чем в тексте программы, то мы увидим крякозябликов. А для многобайтных кодировок у нас будут получаться ещё и странные результаты про длину строк (количество байт) – она будет оказываться больше, чем количество символов в ней – поэтому я и советовал избегать русского языка.

Уникодовская идея о том, что внутри программы любой текст должен иметь универсальное представление, не зависимое от кодировки – правильная. Питон позволяет этой идеей пользоваться. Для этого в питоне есть ещё один тип строк – это "уникодовские строки".

Уникодовские строки обозначаются в питоне префиксом u перед открывающей кавычкой строки:

   1 print u"Привет"

Так как даже при прочтении программы питон должен раскодировать её текст и превратить его в универсальное представление, мы должны ему сообщить о том, в какой кодировке хранится текст программы. Для этого нужно в одной из первых двух строк программы добавить комментарий с текстом: coding: имя кодировки. Редактор IDLE добавляет такой комментарий самостоятельно, если только у вас в тексте программы есть не-английские буквы.

Для работы с кодировками есть две операции:

   1 # coding: cp1251
   2 s = "Привет"
   3 u = s.decode("cp1251") # сработает, если у вас кодировка cp1251
   4 s2 = u.encode("cp1251")
   5 print s2

Кроме того, в питоне команда print самостоятельно переводит уникодные строки в кодировку экрана.

Как прочитать и записать файл в питоне

Для работы с файлом в питоне его сначала нужно "открыть".

В питоне есть два способа работы с файлами:

Нас, очевидно, будет интересовать всегда второй способ.

Обе функции первым аргументом получают имя файла. Вторым аргументом – режим работы с файлом: букву 'r', если мы хотим файл только читать, 'w', если мы хотим в файл только писать. codecs.open имеет ещё и третий аргумент, которым мы указываем, кодировку текста в файле.

Открыв файл, мы получаем файловый объект, вызывая методы которого мы можем что-то делать с файлом.

Самое простое, что можно сделать с файлом – это его открыть и получить весь его текст в виде одной гигантской строки. Для этого у файловых объектов есть метод read:

   1 import codecs
   2 file = codecs.open("hello.txt", "r", "utf-8")
   3 contents = file.read()
   4 print contents

Пока что для простоты мы будем работать только с файлами, лежащими в той же директории, где и наша питонская программа. В этом случае нам достаточно писать только имя файла. Как быть в других случаях, мы будем разбираться позже.

При общении с файлом у питона всегда есть понятие курсора, как в текстовом редакторе. read читает весь файл от текущего места (которое изначально в начале файла) и переводит курсор в конец файла, так что если мы вызовем read ещё раз, на следующий раз он нам вернёт пустую строку.

Самая частая практическая потребность от файлов – это чтение по строкам. Поэтому в питоне сам объект файла является итератором, идущим по строкам файла. (Если убрать слово итератор, то это утверждение полностью эквивалентно такому: если файл запихать в цикл for, то цикл for будет идти по строкам файла, если файл дать аргументом функции list(), то list() вернёт нам список строк в файле):

   1 import codecs
   2 file = codecs.open("hello.txt", "r", "utf-8")
   3 for line in file:
   4     print len(line), line

Если мы хотим записать текст в файл:

   1 import codecs
   2 file = codecs.open("hello.txt", "w", "utf-8")
   3 file.write("Hello,")
   4 file.write(" ")
   5 file.write("world!\n")
   6 file.close()

Бдительный читатель справедливо заподозрит, что sys.stdout, которым мы пользовались на первом занятии, на самом деле есть ни что иное как виртуальный файл, содержимое которого сразу оказывается на экране. Однако я повторяю призыв, что печатать на экран проще с помощью команды print, и давайте мы только ей для этого и будем пользоваться.

Литература