4.3 Работа с файлами#
Разобравшись с устройством путей к файлам и способами взаимодействия с ними, можно перейти к тому, а как работать с самими файлами, лежащими по указанным путям. Так, в данном модуле мы рассмотрим работу с файлами, но с использованием только стандартных средств, без каких-либо сторонних пакетов, требующих дополнительной установки.
Открытие файла#
Для начала работы с любыми файлами нам потребуется знать две вещи:
путь к файлу
способ, которым мы его будем открывать
Про пути мы уже сказали, что они могут указываться как абсолютные, так и относительные. А также пути могут быть в виде строковых переменных, либо объектов Path
Помимо путей нужно определиться со способом открытия, для этого мы будем использовать некоторый «access mode», обычную строковую переменную, которую будем передавать в функцию чтения файла в виде аргумента и которая будет принимать одно из следующих значений:
r- Открытие на чтение. Используется по умолчанию, можно не указывать.w- Открытие на запись. Всегда создает новый файл. Если файл уже существовал, то полностью перезапишет его.x- Открытие на запись с условием, что если файл уже существует, то произойдет ошибка открытия. Более безопасный способ создания новых файлов.a- Открытие на дозапись.
И два дополнительных способа открытия, которые могут комбинироваться с предыдущими:
t- Открытие файла как текстового. Используется по умолчанию, можно не указывать.b- Открытие файла как бинарного.
Определим сразу переменные path и acces_mode
path = r"data/file.txt"
access_mode = "r"
Для чтения файла используется встроенная функция open. Она принимает один обязательный параметр - путь.
Дополнительно могут быть заданы и другие параметры. Так, обычно вторым параметром является способ открытия - уровень доступа. Часто он указывается даже при открытии на чтение, чтобы явно указать цель открытия файла человеку, который будет работать с этим кодом в дальнейшем.
file = open(path, 'r')
file.close() # любой открытый файл нужно в конце закрыть
Также дополнительно может быть указана кодировка, которая будет использоваться при чтении файла.
file = open(path, access_mode, encoding="utf8") # Обычно принято указывать путь, способ открытия и кодировку
text = file.read() # метод чтения, читает весь текст в одну переменную
file.close()
print(text)
1 2 3 4
5 6 7 8
а б с д
Чтение файла#
При открытие файла для него определяется каретка - указатель на то, откуда начать чтение. При выполнении методов, связанных с чтением, каретка сдвигается. После полного прочтения файла каретка остается в конце. Давайте рассмотрим простейший метод чтения файлов и то, как мы можем отслеживать текущее положении каретки, чтобы понимать, что будет прочитано дальше.
file = open(path, access_mode, encoding="utf8")
# С помощью метода tell можно узнать, где каретка сейчас
print("Положение каретки в начале:", file.tell())
text = file.read()
print("Положение каретки после прочтения всего файла:", file.tell())
# С помощью метода seek каретку можно сдвинуть
file.seek(0)
print("Положение каретки после сдвига:", file.tell())
# В функции чтения можно передать число, которое ограничит количество читаемых символов
text = file.read(5)
print("Положение каретки в конце:", file.tell())
print("Прочитанный текст:", text)
file.close()
Положение каретки в начале: 0
Положение каретки после прочтения всего файла: 27
Положение каретки после сдвига: 0
Положение каретки в конце: 5
Прочитанный текст: 1 2 3
Другие методы для чтения
# readline - читает только одну строку
file = open(path, access_mode, encoding="utf8")
text_line_1 = file.readline(3) # В функцию можно передать число, которое ограничит количество читаемых символов
text_line_2 = file.readline() # Читает с текущего положения каретки до символа переноса строки (либо до указанного ограничения)
print(text_line_1)
print(text_line_2)
file.close()
1 2
3 4
# readlines - читает файл в список из строк
file = open(path, access_mode, encoding="utf8")
text_lines = file.readlines(10) # В функцию можно передать число, которое ограничит количество читаемых символов
# Если ограничение попало в середину строки, то она все равно будет прочитана полностью
print(text_lines)
file.close()
['1 2 3 4\n', '5 6 7 8\n']
Зачастую чтение файлов будет строиться таким образом, что можно будет никак не ограничивать чтение и просто читать файл построчно в цикле:
file = open(path, access_mode, encoding="utf8")
for line in file.readlines():
print(line)
file.close()
1 2 3 4
5 6 7 8
а б с д
file = open(path, access_mode, encoding="utf8")
for line in file: # при итерациях по файлу перебираются именно строки
print(line)
file.close()
1 2 3 4
5 6 7 8
а б с д
Запись файла#
Если при чтении файла у нас была функция для чтения файла в одну текстовую переменную - read и функция для чтения построчно в список из строк readlines, то для записи по аналогии используются write - для записи одной текстовой переменной в файл и writelines - для записи последовательности текстовых переменных.
new_path = r"data/text.txt"
file = open(new_path, "w", encoding="utf8") # Запись всегда создает новый файл
file.write("string1") # Также используется каретка, запись происходит в месте, где она находится, и передвигает её
file.write(str(123)) # Можно записать только строки. Разделителей строк по умолчанию нет.
file.close()
file = open(new_path, "w", encoding="utf8")
file.writelines(["string1", str(123)]) # Как вариант можно записать список из строк, разделителей также не будет
file.close()
file = open(new_path, "w", encoding="utf8")
file.write("string1\n") # Переносы строк нужно расставлять вручную
file.write("\n".join(["string2", "string3", "444"])) # Либо можно воспользоваться методом строк join
file.close()
Пользуясь переносом каретки, текст можно записать в любое место файла, а если файл открыть на дозапись, то его можно изменить так, как необходимо. Однако большинство задач будет требовать простой последовательной построчной записи в файлы.
Контекстный менеджер#
В текущем варианте работы с файлами легко упустить момент, связанный с закрытием файла по завершении работы с ним. Чтобы автоматически выполнять операции закрытия, в Python есть понятие контекстного менеджера. Контекстный менеджер - это механизм, позволяющий нам создать новую переменную и определить блок инструкций связанный с ней, а при выходе из этого блока инструкций автоматически выполнить некоторый код для завершения работы с переменной.
Так, в нашем случае мы сможем автоматически закрыть файл. А также подобным образом могут закрываться соединения с базами данных, подключения к интернет-ресурсам и тому подобное.
Контекстный менеджер реализуется с помощью конструкции with.
Работа с файлами практически всегда осуществляется с её помощью.
with <Выражение> as <Переменная>:
Блок инструкций
Условно можно сказать, что конструкция with работает как операция присваивания, а по завершении блока закрывает переменную (выполняет для неё метод __exit__, для файлов внутри метода __exit__ вызывается метод close)
with open(path, encoding="utf8") as file:
lines = file.readlines()
print(lines)
['1 2 3 4\n', '5 6 7 8\n', 'а б с д']
В конструкции with может быть открыто сразу несколько файлов. Главное - следить, чтобы сохранялась читаемость кода
with open(path, encoding="utf8") as file, open(new_path, "w", encoding="utf8") as new_file:
lines = file.readlines()
new_file.writelines(lines)
Практические задания