Перейти до змісту

Щоб не загрузити пам`ять треба читати з файлу по одному рядку: Краще так:

with open("somefile.txt", "r") as file:
    for line in file:
        print(line)

(file.close() не треба бо використовується контекст менеджер а також виключається можливість помилок якщо файл завеликий, бо читання йде построково)

Запис:

with open("somefile.txt", "w") as file:
    file.write("something")

Приклад:

with (open(args_list[1], "r") as read_file,
     open(args_list[2], "a") as write_file):
    for line in read_file:
        write_file.write(line)

Функція open та close

Робота з файлами

В цьому розділі ми розглянемо, навіщо потрібні файли та як з ними працювати.

Використання файлів

Іноді нам доводиться працювати з файлами. Наприклад, коли є потреба у довготривалому зберіганні інформації про виконання програми. Це особливо корисно, якщо ви запускаєте програму регулярно. Необхідно записувати та логувати, чи вона запустилася і відпрацювала, чи не спрацювала коректно і завершилася. Одне з рішень проблеми довготривалого зберігання інформації — це запис у файл. Але потрібно розуміти, що якщо є можливість запису у файл, повинна бути і можливість читання цього файлу, його редагування або видалення.

Дії з файлами

Тепер ми розглянемо дії, доступні для роботи з файлами в Python.

Режими відкриття

Перед початком роботи з файлом та виконанням дій над ним, його необхідно відкрити. Це можна зробити за допомогою вбудованого методу open(). В круглих дужках спочатку вказуємо шлях до файлу, а потім режим, в якому хочемо відкрити файл.

Якщо не вказати режим, файл автоматично відкриється в режимі tr за замовчуванням, що означає читання в текстовому режимі.

Розглянемо, які режими файлів існують:

  • r — читає файл і повертає помилку, якщо файл не існує;
  • w — записує дані у файл і створює новий файл, якщо він не існує, або перезаписує існуючий файл;
  • a — дописує дані у файл, і створює файл, якщо він не існує, або додає нову інформацію в кінець існуючого файлу;
  • x — записує дані у файл і повертає помилку, якщо файл вже існує (ексклюзивне створення);
  • t — використовується тільки для текстових файлів (текстовий режим — ми бачимо текст);
  • b — використовується для нетекстових файлів, таких як зображення, відео тощо (бінарний режим — ми бачимо 0 і 1);
  • + — дозволяє працювати в режимах читання і запису одночасно.

А тепер подивимося, як це працює. Нехай у нас є файл "errors.txt", який містить наступні дані:

10:53 12/09/2022 too many requests
21:17 13/09/2022 user admin not found

Ми можемо відкрити цей файл наступним чином:

file = open("errors.txt")

В цьому прикладі файл було відкрито в режимі tr за замовчуванням, оскільки ми не вказали, який режим нам потрібен.

Тепер відкриємо цей самий файл у режимі читання:

file = open("errors.txt", "r")

Зверніть увагу: немає різниці між режимами r та tr, оскільки текстовий режим є режимом за замовчуванням.

Закриття

Поки що ми навчилися лише відкривати файли, але закриття є обов'язковою процедурою при роботі з файлами.

Уявіть, що ви запустили великий проект, який часто записує інформацію у файл. Далі ви забули закрити файл, і програма продовжує працювати, навіть якщо вам більше не потрібно писати у файл.

Через деякий час файл буде заповнений непотрібною інформацією, і великий обсяг пам'яті комп'ютера буде зайнятий цією інформацією, що призведе до системних помилок. Щоб уникнути такого сценарію, обов'язково закривайте файл після використання.

Це можна зробити за допомогою вбудованого методу close(). Ось приклад, як це працює:

file = open("errors.txt", "r")
file.close()

Читання

Для читання всього файлу в одну змінну використовуйте метод read().

file = open("errors.txt", "r")

print(file.read())
# 10:53 12/09/2022 too many requests
# 21:17 13/09/2022 user admin not found

file.close() # І не забудьте закрити файл

Якщо передати числовий аргумент у метод read(), він поверне вказану кількість символів з файлу:

file = open("errors.txt", "r")
print(file.read(10))    # 10:53 12/0
file.close()

Щоб почати читання не з початку файлу, використовуйте метод seek() і вкажіть кількість символів, які потрібно пропустити:

file = open("errors.txt", "r")

file.seek(10)
print(file.read())
# 9/2022 too many requests
# 21:17 13/09/2022 user admin not found

file.close()

Для построкового читання файлу створіть цикл і використовуйте метод readline() або readlines(). Метод readline() повертає рядок з файлу при виклику, а метод readlines() повертає всі рядки файлу у вигляді списку, де кожен елемент є рядком файлу. Наприклад:

file = open("errors.txt", "r")

print("Readline method working")
print(file.readline())

file.close()

В консолі ви побачите:

Readline method working
10:53 12/09/2022 too many requests

А ось приклад методу readlines():

file = open("errors.txt", "r")

line_number = 1     # Змінна для відображення номера рядка
print("Readlines method working")
for line in file.readlines():
    print(f"Line number {line_number}")
    print(line)
    line_number += 1

file.close()

В консолі ви побачите:

Readlines method working
Line number 1
10:53 12/09/2022 too many requests
Line number 2
21:17 13/09/2022 user admin not found

Цікава особливість цих методів полягає в тому, що тут не виникне проблем з пам'яттю — в один момент ми читаємо лише 1 рядок з файлу, а не весь файл, як у випадку з методом read(). Тому навіть якщо файл величезний, ми все одно можемо обробити його, читаючи рядок за рядком (так, це може бути тривалий процес, але все ж можливий).

Інший спосіб построкового читання — ітерація за допомогою циклу for без додаткових методів:

file = open("errors.txt", "r")

line_number = 1     # Змінна для відображення номера рядка
for line in file:
    print(f"Line number {line_number}")
    print(line)
    line_number += 1

file.close()

В консолі ви побачите:

Line number 1
10:53 12/09/2022 too many requests
Line number 2
21:17 13/09/2022 user admin not found

Запис та дописування

Для запису інформації у файл використовуйте режим w — запис. Відкриття файлу в режимі запису створює новий файл, якщо він не існує, або перезаписує існуючий файл. Один із способів запису інформації у файл — це вбудований метод write().

Зверніть увагу: в метод write() можна передавати тільки рядки як аргументи:

file = open("errors.txt", "w")
file.write("17:00 14/09/2022 value error")

file.close()

Тепер файл "errors.txt" містить рядок "17:00 14/09/2022 value error". Стара інформація з файлу була перезаписана новою.

Щоб дописати дані у файл без втрати існуючої інформації, потрібно відкрити файл у режимі a — дописування. Цей режим створює файл, якщо він не існує, або додає нову інформацію в кінець існуючого файлу. Для запису інформації також використовуйте метод write():

file = open("errors.txt", "a")
file.write("17:00 14/09/2022 value error")

file.close()

Тепер, якщо ми прочитаємо файл, в консолі побачимо:

10:53 12/09/2022 too many requests
21:17 13/09/2022 user admin not found
17:00 14/09/2022 value error

Ви можете побачити різницю між режимами запису та дописування на цих прикладах. У першому прикладі існуюча інформація була замінена новою. У другому прикладі нова інформація була записана після існуючої в кінці файлу.

Контекстні менеджери у файлах

Але що станеться, якщо ви забудете закрити файл після відкриття? Краще нам цього не дізнаватися. Python може це запобігти. Для цього — використовуйте контекстні менеджери.

Контекстні менеджери часто пов'язані з оператором with. Обгорнувши роботу з файлом у контекстний менеджер — він автоматично закриє файл при виході з цієї області.

Розглянемо два подібні приклади:

# Рішення 1

file = open("errors.txt", "r")
# Деякі дії з файлом
file.close()


# Рішення 2

with open("errors.txt", "r") as file:
    # Деякі дії з файлом

Як бачите, в обох рішеннях файл відкривається та закривається. Але другий варіант займає менше місця, виглядає елегантніше і гарантує закриття файлу, навіть якщо ви забудете про це.

Ви повинні завжди використовувати контекстні менеджери, тому що коли виникає помилка між відкриттям та закриттям файлу, програма завершується, але контекстний менеджер закриє файл, навіть якщо виникла помилка.

Наприклад, цей файл буде закрито:

with open("errors.txt", "w+") as file:
    file.read()
    file.write(1/0)

Зверніть увагу: контекстний менеджер працює не тільки з файлами. Різні приклади його використання будуть розглянуті далі в інших темах.

Основні моменти, які потрібно пам'ятати при роботі з контекстними менеджерами:

  1. Контекстний менеджер завжди містить два спеціальні методи: __enter__ та __exit__.
  2. Метод __enter__ повертає об'єкт, присвоєний змінній після ключового слова as. Значення за замовчуванням — None, і воно необов'язкове.
  3. Якщо помилка виникає в __init__ або __enter__, блок коду не виконується і __exit__ не викликається.
  4. Після входу в блок коду __exit__ завжди викликається, навіть якщо в ньому виникає виключення.

Структура контекстного менеджера:

class CustomContextManager():
    def __init__(self):
        pass

    def __enter__(self):
        pass

    def __exit__(self):
        pass

    def __del__(self):
        pass

Контекстні менеджери

Як влаштований:

with open("filename.txt", "r") as f:
    f.read()

Приблизно так: