Работаем с файловым вводом/выводом в Python

Учим основы работы с файлами в Python. Как читать из файлов, как записывать в них данные, что такое поиск по файлу и почему файлы нужно закрывать.

В этой статье вы научитесь работе с файлами в Python.

Возможность чтения и записи файлов — важная особенность любого языка. Без нее все переменные и информация хранятся в оперативной памяти и пропадают, когда компьютер выключается или программа завершается. КОгда сохраняешь данные в файл, их можно позже спокойно извлечь.

Вот о чем сегодня пойдет речь:

  • Разница между бинарными и текстовыми файлами
  • Где искать встроенные средства Python для ввода/вывода
  • Как открыть и закрыть файл
  • Различные способы чтения данных из файлов
  • Как записать данные в файловый объект
  • Поиск внутри файла и перемещение указателя
  • Редактирование существующего текстового файла

Приступим!

Бинарные vs текстовые файлы

Следует различать два типа файлов, с которыми работает Python: бинарные и текстовые. Важно понимать разницу между ними и с ними работать.

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

  • Картинки .jpg.png.bmp.gif.
  • Файлы баз данных .mdb.frm, и.sqlite
  • Документы .doc.xls.pdf, и др.

Эти фалы имеют свои особенности и требуют специального софта для открытия. НАпример, чтобы открыть файл  .xls, нужен Excel. Чтобы открыть базу данных, тоже нужна специальная программа.

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

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

Дополнительно, текстовые файлы содержат невидимые символы в конце каждой строки, которые помогают редактору понять, что строка закончилась. При работе с файлами программно, можно использовать эти символы. В Python этот символ «\n»

Где искать средства работы с вводом/выводом

В Python для работы с файлами не нужно импортировать сторонние библиотеки, все идет в комплекте.

В других языках, таких как С++, для работы с файлами необходимо подключить средства файлового ввода/вывода  #include <fstream>. А если вы пишете на Java, то вам нужно прописать  import java.io.*

C Python в этом нет необходимости. Наоборот, в  Python есть встроенный набор функций, которые позволяют делать все, что нужно для чтения и записи файлов. ПОсмотрим на них поближе.

Открытие файлов в Python

Первая функция, с которой мы познакомимся —  open()

И в Python2, и в  Python3 эта команда возвращает файловый объект. Базовое использование выглядит так:

file_object = open(filename, mode)

Здесь  filename это имя файла, с которым вы хотите работать, вместе с расширением. Например, если у вас есть текстовый файл  workData.txt , нужно указывать имя файла именно с расширением.

Вы можете также указать полный путь до файла, например,  “C:\ThisFolder\workData.txt” , если используете Windows.

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

К счастью, в Python можно пойти двумя путями для решения данной проблемы. Первый путь — использовать двойной обратный слэш:  "C:\\ThisFolder\\workData.txt" . Второй — использовать прямые слэши  "C:/ThisFolder/workData.txt"

Параметр  mode  при открытии файла говорит Python что вы хотите сделать с файлом. Есть несколько режимов, которые можно указать при работе с текстовыми файлами:

  • 'w' – Режим записи: Этот режим используется, когда файл нужно заменить. Имейте в виду, что в этом режиме существующий файл стирается и создается новый . Указатель помещается в начало файла.
  • 'r' – Режим чтения: Этот режим используется, когда нужно только прочитать информацию из файла и ничего не менять. Указатель помещается в начало файла.
  • 'a' – Режим добавления: В этом режиме информация добавляется в конец файла. Указатель помещается в конец файла.
  • 'r+' – Режим чтения/записи: Используется, когда вы будете вносить изменения в файл и читать информацию из него. Указатель помещается в начало файла.
  • 'a+' – Режим добавления и чтения:  Файл открывается для добавления данных в конец, при этом можно читать информацию из файла. Указатель помещается в конец файла.

При работе с бинарными файлами используются те же режимы. Однако, необходимо добавлять  b  в конце. Таким образом, режим записи выглядит так:  'wb' . Остальные режимы —  'rb', 'ab', 'r+b'  и  'a+b'

В Python 3 добавлен еще один режим:

  • 'x' – Режим эксклюзивного создания: Этот режим используется исключительно для создания файла. Если файл с указанным именем уже существует, вы получите ошибку.

Давайте разберем открытие файла и установку режима на примере.

При использовании  open() обычно результат выполнения сохраняется в переменной. Если у нас есть файл  workData.txt, то правильно его открыть на чтение и запись выглядит так:

data_file = open("workData.txt", "r+")

Этот код создает объект  data_file  , которым мы в дальнейшем можем манипулировать с помощью методов файлового объекта Python.

Мы использовали режим доступа 'r+' , чтобы указать Python, что мы хотим открыть файл для чтения и записи. Такой подход дает большую гибкость, но часто можно использовать просто режим чтения или просто записи  и здесь.

Закрытие файла в Python

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

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

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

Для закрытия используется простая функция  fileobject.close() . Для нашего файлового объекта  data_file  это будет выглядеть так:

data_file.close()

После того, как файл закрыт, вы уже не можете получить к его содержимому пока заново не откроете. Попытка чтения закрытого файлового объекта приведет к исключению  ValueError exception:

>>> f = open("/tmp/myfile.txt", "w")
>>> f.close()
>>> f.read()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    f.read()
ValueError: I/O operation on closed file.

В Python лучшей практикой открытия и закрытия файлов считается использование ключевого слова  with . При его использовании закрытие файла происходит автоматически при достижении конца блока

with open("workData.txt", "r+") as workData:
    # File object is now open.
    # Do stuff with the file:
    workData.read()

# File object is now closed.
# Do other things...

Если вы не используете ключевое слово  with или используете функцию  fileobject.close() , то Python автоматически закроет и уничтожит файловый объект с помощью встроенного сборщика мусора.Однако, в зависимости от вашего кода, сбор мусора может произойти в любое время. Поэтому рекомендуется использовать  with , чтобы контролировать когда файл закрывается — в конце внутреннего блока оператора.

Работаем с файловыми объектами Python

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

Далее вы научитесь читать данные из открытого файла:

Чтение данных из файла в Python

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

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

Параметр  size указывает методу чтения сколько байт из файла отобразить. Предположим, что наш файл “workData.txt” содержит следующий текст:

This data is on line 1
This data is on line 2
This data is on line 3

Если вы  напишете на Python 3

with open("workData.txt", "r+") as work_data:
    print("This is the file name: ", work_data.name)
    line = work_data.read()
    print(line)

то получите

This is the file name: workData.txt
This data is on line 1
This data is on line 2
This data is on line 3

А если третью строку поменять на

line = workData.read(6)

то получим следующий вывод:

This is the file name: workData.txt
This d

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

Если вы хотите прочитать данные из того же файлового объекта, он продолжит с того места, на котором остановился. ТАкой метод можно использовать для чтения больших файлов.

Построчное чтение файлов с помощью readline()

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

Метод  fileobject.readline(size)  по умолчанию возвращает перву строку. Меняя параметр  size , можно получить любую строчку из файла.

Например:

with open("workData.txt", "r+") as work_data:
     print("This is the file name: ", work_data.name)
     line_data = work_data.readline()
     print(line_data)

выведет

This is the file name:  workData.txt
This data is on line 1

Подставив 2 или 3 в параметр  size , получим 2 и 3 строки соответственно.

Схожий метод  fileobject.readlines()  возвращает каждую строку в виде кортежа. Если написать

print(work_data.readlines())

то получим следующий вывод:

['This data is on line 1', 'This data is on line 2', 'This data is on line 3']

Как видите, метод считывает весь файл в память и делит его на строки. Работает он только с текстовыми файлами. Бинарный файл не имеет строк, это просто кусок данных.

Построчная обработка текстового файла целиком

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

with open("workData.txt", "r+") as work_data:
    for line in work_data:
        print(line)

Он выведет нам следующее:

This data is on line 1
This data is on line 2
This data is on line 3

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

Запись в файл с использованием write()

Зачем нужны файлы, если в них нельзя ничего записать? Давайте обсудим.

Вспомните, при создании нового файлового объекта Python создаст файл, если он еще не существует. ПРи создании нового файла в первы раз, нужно использовать режим a+ или w+.

Часто предпочтительнее использовать a+, потому что по умолчанию данные будут дописаны в конец файла. В режиме w+ существующие данные будут удалены.

По умолчанию для записи в файл используется метод  fileobject.write(data) . Например, можно добавить строчку в наш файл с помощью ледующего кода:

work_data.write("This data is on line 4\n")

Символ \n действует как индикатор конца строки, перемещая следующую операцию записи на следующую строку.

Если вы хотите записать что-то, что не является строкой, в текстовый файл, такое как числа, нужно конвертировать их в строки.

Например, если бы вы хотели добавить целые числа 1234б 5678б 9012 в файл, то сделали бы следующее. Во-первых, преобразовали все числа в строки, а затем записали эти строки в файловый объект:

values = [1234, 5678, 9012]

with open("workData.txt", "a+") as work_data:
    for value in values:
        str_value = str(value)
        work_data.write(str_value)
        work_data.write("\n")

Поиск по файлу: перемещение указателя ввода/вывода

Как вы помните, при использовании режима a+ ваш файловый указатель всегда помещается в конец файла. В коды выше мы записали в файл 3 числа. Метод  fileobject.write() ничего не возвращает, потому что он следит за указателем в поисках дополнительного текста.

Что нужно сделать, так это переместить указатель обратно в начало файла. Простейший способ сделать это — использовать метод  fileobject.seek(offset, from_what) .  Этот метод позволяет установить указатель в определенное место.

Смещение  offset это количество символов от  from_what . Параметр  from_what может иметь 3 значения:

  • 0 – начало файла
  • 1 – текущая позиция указателя
  • 2 – конец файла

При работе с текстовыми файлами (которые были открыты не в бинарном режиме), можно использовать только значение по умолчанию 0, или  seek(0, 2) , чтобы переместиться в конец файла.

Так что, если использовать  work_data.seek(3, 0)  для нашего файла, то мы поместим указатель на 4й символ (отсчет начинается с нуля). Если использовать цикл по строкам, то вы получите:

s data is on line 1
This data is on line 2
This data is on line 3

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

with open("workData.txt", "a+") as work_data:
    print(work_data.tell())

Он вернет 69б что соответствует дине файла

Редактирование существующего текстового файла в Python

Рано или поздно наступает момент, когда вам нужно редактировать файл, а не просто добавлять в него данные. Нельзя просто использовать режим w+. Вспомните, режим w полностью перезапишет файл, поэтому даже используя  fileobject.seek() , сделать это не получится. А a+ всегда будет вставлять данные в конец файла.

Простейший способ сделать то, что мы хотим — взять весь файл и создать из него список или массив данных. Когда список создан, можно использовать метод  list.insert(i, x)  для вставки новых данных.

Когда новый список создан, можно объединить его и записать в файл.

Помните, что для  list.insert(i, x) , i — целое число, указывающее на номер ячейки. Содержимое x затем помещается перед ячейкой i.

Например, мы хотим в наш файл вставить строку «This goes between line 1 and 2». Код получится таким:

# Open the file as read-only
with open("workData.txt", "r") as work_data:
    work_data_contents = work_data.readlines()

work_data_contents.insert(1, "This goes between line 1 and 2\n")

# Re-open in write-only format to overwrite old file
with open("workData.txt", "w") as work_data:
    work_dataContents = "".join(work_data_contents)
    work_data.write(work_data_contents)

Если после запуска этого кода сделать

with open("workData.txt", "r") as work_data:
    for line in work_data:
        print(line)

то получим следующий вывод

This data is on line 1
This goes between line 1 and 2
This data is on line 2
This data is on line 3

Мы увидели как отредактировать существующий файл в Python, вставив новую строку в нужное нам место.

В данной статье вы научились основам работы с файлами в Python. Вот что мы узнали:

  • Разница между текстовыми и бинарными файлами
  • Где искать встроенные функции работы с файлами
  • Как открывать и закрывать файлы в Python
  • Различные способы чтения данных из файла в Python
  • Как записать данные в файловый объект в Python
  • Поиск по файлу и перемещение указателя
  • Редактирование существующего текстового файла

Оригинал статьи

Ссылка на основную публикацию