Лекция 5. Файлы

Файлы. Чтение и запись

Для того, чтобы открыть файл, предпочтительнее всего использовать функцию open в связке с блоком with, который умеет автоматически закрывать открытые файлы.

Чтение файлов:

with open('1.txt', 'r') as f:     # f здесь -- имя переменной для файла.
    # Здесь мы работаем с открытым файлом.
# Как только мы выйдем за пределы блока инструкций с отступами,
# который принадлежит конструкции with, файл автоматически будет закрыт.

При записи в файл второй аргумент функции open меняется на ‘w’ (write), при этом режиме работы размер файла с заданным именем будет усечён до нуля, и запись начнётся с начала пустого файла.

with open('1.txt', 'w') as f:
    # Запись в файл.

В обоих случаях Python работает с текстовыми файлами в кодировке UTF-8. Если необходимо открыть файл в другой кодировке, например, в кодировке Windows для русского языка, CP1251, надо вызывать open следующим образом:

with open('1.txt', 'r', encoding='cp1251') as f:
    # читаем файл в кодировке cp1251, строки автоматически декодируются
    # во внутреннее представление Python3

Здесь и далее в этих лекциях мы рассматриваем только текстовые файлы. Если вы хотите работать с бинарными файлами, необходимо открывать их в режимах 'rb' и 'wb' вместо 'r' и 'w'. Из таких файлов вместо строк считываются массивы байт (тип bytearray). С ним вы можете познакомится в других материалах по языку Python.

Чтение файлов

Открытый файл можно считывать следующими способами:

c = f.read(1) # Считает из файла один символ и вернёт его
text = f.read()  # Считает весь файл в одну строку и вернёт её
line = f.readline()  # Считает из файла строку и вернёт её
lines = f.readlines()  # Считает весь файл и вернёт список строк в нём

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

with open('1.txt', 'r') as f:
    a = f.read(1)
    b = f.read(1)
    c = f.read()
    d = f.readline()

то в a будет лежать первый символ, в b второй, в c все остальные символы, начиная с третьего, а в d пустая строка, так как весь файл уже считан и позиция чтения находится в конце файла. Вызовы всех методов считывания в конце файла будут возвращать пустую строку ''.

Кроме того, позицию считывания можно изменять вручную. Если нужно “отмотать” файл в начало, используйте:

f.seek(0)

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

pos = f.tell()

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

f.seek(pos)

Для построчного чтения файлов можно просто использовать файловый объект в цикле for:

for line in f:
    # Тело цикла будет запускаться для каждой строки файла f.
    # Все строки, кроме последней, имеют '\n' на конце.
    # Будет ли '\n' на конце последней строки, зависит от того,
    # есть ли он там в самом файле f.

Такой способ предпочтительнее, чем использование f.readlines(), так как readlines считает все строки и выделит под них память, что может привести к проблемам со свободной памятью на файлах очень большого размера. for же будет считывать файл построчно и выделять память только под текущую строку.

Запись в файлы

Базовой возможностью для записи в файлы является метод write, который записывает строку в файл. Если ему передать что-нибудь кроме строки, он выдаст ошибку. В отличие от функции print, метод write записывает в файл только саму строку, не добавляя автоматически перевод строки. Если он нужен, его надо добавить самостоятельно.

f.write('hello, world!\n')
f.write(str(123) + '\n')

Кроме того, для печати текста в файлы отлично подходит и сама функция print с именованным аргументом file:

print('hello, world', file=f)
print(123, file=f)

Посимвольное чтение

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

while True:
    c = f.read(1)
    if c == '':
        break
    print(ord(c), repr(c))