Функция open. Чтение данных из файла

Курс по Python: https://stepik.org/course/100707

На этом занятии мы с вами научимся читать данные из файлов. Думаю, вы все прекрасно понимаете, что такое файлы и что они хранятся, как правило, на внешних носителях. (Часто – это жесткий диск устройства или флеш-память или SSD-диск. Бывают и другие носители). Главная особенность файлов – сохранение информации после отключения устройства от питания.

Начнем со знакомства с функцией:

open(file [, mode=’r’, encoding=None, …])

которая открывает указанный файл на чтение или запись данных (по умолчанию – на чтение). Основные ее параметры, следующие:

  • file – путь к файлу (вместе с его именем);
  • mode – режим доступа к файлу (чтение/запись);
  • encoding – кодировка файла.

Чтобы воспользоваться этой функцией, нужно правильно записать первый аргумент – путь к файлу. Давайте, посмотрим различные варианты его определения. Представим, что наш файл ex1.py находится в рабочем каталоге app:

Тогда, чтобы обратиться к файлу my_file.txt путь можно записать просто, как:

"my_file.txt"

или

"d:\\app\\my_file.txt"

или так:

"d:/app/my_file.txt"

Последние два варианта представляют собой абсолютный путь к файлу, то есть, полный путь, начиная с указания диска. Причем, обычно используют обратный слеш в качестве разделителя: так короче писать и такой путь будет корректно восприниматься как под ОС Windows, так и Linux. Первый же вариант – это относительный путь (относительно каталога с исполняемым файлом).

Теперь, предположим, что мы хотим обратиться к файлу img.txt. Это можно сделать так:

"images/img.txt"

или так:

"d:/app/images/img.txt"

Для доступа к out.txt пути будут записаны так:

"../out.txt"
"d:/out.txt"

Обратите внимание, здесь две точки означают переход к родительскому каталогу, то есть, выход из каталога app на один уровень вверх.

И, наконец, для доступа к файлу prt.dat пути запишутся так:

"../parent/prt.dat"
"d:/ parent/prt.dat"

Вот принцип, по которому прописываются пути к файлам. В нашем случае мы имеем текстовый файл «my_file.txt», который находится в том же каталоге, что и программа ex1.py, поэтому путь можно записать, просто указав имя файла:

file = open("my_file.txt")

В результате переменная file будет ссылаться на файловый объект, через который и происходит работа с файлами. Если указать неверный путь, например, так:

file = open("my_file2.txt")

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

Итак, функция open() по умолчанию открывает файл на чтение. Это значит, что в этом режиме мы можем только считывать информацию из файла, но не записывать. Как прочитать данные из файла? Для этого существует несколько методов у файлового объекта. Например, если выполнить метод:

print( file.read() )

то будет прочитан весь файл целиком и результат представлен в виде строки. Но сейчас мы видим с вами в консоли отображаются какие-то кракозябры. Почему? Все дело в несовпадении кодировок. В моем случае метод read() читает данные в кодировке windows-1251, а кодировка файла с текстом – UTF-8. Чтобы это поправить, в функции open() нужно явно указать кодировку файла через именованный аргумент encoding:

file = open("myfile.txt", encoding="utf-8" )

Теперь все работает корректно. Но, что если нам нужно прочитать из файла всего несколько символов? Для этого достаточно вызвать метод read() и первым аргументом указать максимальное количество читаемых символов, например:

print( file.read(4) )

Из файла будут считаны первые четыре символа. Правда, в консоли мы видим только три символа. Дело в том, что при кодировке UTF-8 в файл автоматически добавляется первый (невидимый) символ с шестнадцатиричным кодом:

#FEFF

Если мы снова вызовем метод:

print( file.read(4) )

то будут прочитаны следующие четыре символа. Вот эта стрелка (на рисунке) называется файловой позицией (file position), которая указывает, с какого места производить последующее считывание информации. Благодаря ей мы можем последовательно читать данные, просто вызывая метод read(). Когда доходим до конца файла, то здесь находится специальный символ EOF, означающий конец файла.

При необходимости, мы можем управлять положением файловой позиции. Для этого существует специальный метод:

file.seek(offset[, from_what])

Например, вот такая запись:

file.seek(0)

будет означать, что мы устанавливаем позицию в начало и тогда такие строчки:

    print( file.read(4) )
    file.seek(0)
    print( file.read(4) )

будут считывать одни и те же первые символы. Если же мы хотим узнать текущую позицию в файле, то следует вызвать метод tell:

pos = file.tell()
print( pos )

Следующий полезный метод readline() позволяет построчно считывать информацию из текстового файла:

    s = file.readline()
    print( s )

Здесь концом строки считается символ переноса ‘\n’, либо конец файла. Причем, этот спецсимвол переноса будет также присутствовать в строке. Мы в этом можем убедиться, вызвав дважды функцию:

    print( file.readline() )
    print( file.readline() )

Здесь в консоли строчки будут разделены пустой строкой. Это как раз из-за того, что один перенос идет из прочитанной строки, а второй добавляется самой функцией print(). Поэтому, если их записать вот так:

    print( file.readline(), end="" )
    print( file.readline(), end="" )

то вывод будет построчным с одним переносом.

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

    for line in file:
        print( line, end="" )

Этот пример показывает, что объект файл является итерируемым и на каждой итерации возвращает очередную строку.

Или же, все строчки можно прочитать методом:

s = file.readlines()

и тогда переменная s будет ссылаться на список с этими строками:

print( s )

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

По сути это все методы для считывания информации из файла. Осталось только добавить, что как только мы завершаем работу с файлом, его следует закрыть. Для этого используется метод close:

file.close()

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

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

Курс по Python: https://stepik.org/course/100707

Видео по теме