loading...

08.05.2020

Уроки Python: Работа с файлами.

Основы

Работа в Python с файлами в большинстве случаев заключается в открытии файла, его чтении (построчно или целиком) и/или записи.
Список функции, которые обычно используются для этого:

  • open()
  • .read()
  • .write()
  • .close()
  • .tell()
  • .seek()

Так же хочу отметить проект для поддержки асинхронной работы с файлами: https://github.com/mosquito/aiofile
Об aiofile я расскажу в конце данной статьи.

А сейчас я подробнее расскажу о каждом методе для работы с файлами.

Открытие файла — open()

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

Синтаксис open()

file = open(file_name, [, mode])

Здесь приведён минимальный пример использования функции open для открытия файла.

Первый аргумент функции open это путь до файла (file_name). Обычно это строка (абсолютный или относительный путь), но так же возможно использование path-like объекта (об этом я расскажу чуть позже).

Второй аргумент — это режим (mode) в котором открывается файл. По-умолчанию mode='r', что значит что файл открывается только на чтение (запись невозможна). При попытке вызвать метод .write у файла, открытого только на чтение вы получите ошибку (исключение):

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
io.UnsupportedOperation: not writable

Ниже приведена таблица возможных значений аргумента mode:

РежимОписание
'r'Открыть файл только на чтение (запись невозможна, по умолчанию)
'w'Открыть файл на запись (файл полностью очищается)
'x'Открыть файл на запись, если файла не существует, иначе исключение
'a'Открыть файл на запись, но данные добавляются в конец файла (append)
'b'Открыть файл в двоичном (binary) режиме
't'Открыть файл в текстовом режиме (по умолчанию)
'+'Открыть на чтение и запись (редко используется)
Возможные значения аргумента mode при открытии файла

Режиме (mode) могут быть объединены, например, 'rb' — открыть файл на чтение в двоичном режиме (частый кейс). Значение mode по умолчанию — 'rt' (открытие файла на чтение в текстовом режиме), то есть если вам надо открыть обычный текстовый файл только на чтение — mode можно не указывать (но обычно всё же указывают). Варианты использования различных режимов я покажу в других главах статьи.

Пример открытия файла

Есть 2 основных способа открыть файл в Python:

  1. Без использования менеджера контекста
  2. С использованием менеджера контекста (подробнее о нём я расскажу позже)

Без использования менеджера контекста

С одной стороны этот вариант открытия файла проще, но с другой — скрывает в себе подводные камни.
Листинг 1.1, пример:

f = open('some_file.txt', mode='w')
f.write('a')
f.close()

В примере выше код полностью корректен, но проблема заключается в том что если в момент записи в файл (f.write) произойдёт ошибка (например, какая-то системная), то f.close() никогда не вызовется, а значит файл не будет закрыт. Поэтому рекомендуется использовать другой вариант открытия файла — с помощью менеджера контекста.

Открытие файла с использованием менеджера контекста

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

with open('some_file.txt', mode='w') as f:
    f.write('a')

Код стал ещё короче! По функциональности эти 2 примера идентичны, но закрытие файла во втором случае (при использовании менеджера контекста) происходит автоматически при выходе из менеджера контекста (даже если внутри произошла ошибка).

Чтение файла .read()

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

f.read([size])

Необязательный аргумент size отвечает за количество байт, которые будут прочитаны из файла. Если не передать этот аргумент, то файл будет прочитан полностью.

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

Для начала создайте файл с текстом (shell):

cat > some_file.txt << 'EOL'
First line
Second line
EOL

Либо просто создайте файл с несколькими строками текста в вашем любимом редакторе.
После этого выполните в python интерпретаторе код (сохраните его в файл и выполните файл или просто запустите в python консоли REPL).
Листинг 1.3:

with open('some_file.txt', mode='r') as f:
    print(f.read())

Результат выполнения кода:

First line
Second line

(или те строки текста, которые вы написали в текстовом файле).

Здесь всё очень просто:

  1. 1я строка (with … as …) открыла файл some_file.txt на чтение.
  2. 2я строка print(f.read()) прочитала весь файл и с помощью print() вывела его содержимое на экран.

Пример чтения файла построчно

Для того чтобы прочитать файл построчно используется цикл for.
Листинг 1.4, пример построчного чтения файла:

with open('some_file.txt', mode='r') as f:
    for line in f:
        print(line)

Пример чтения файла частично

Для того чтобы прочитать файл не весь сразу, а только часть (например 7 байт) — надо просто в метод .read() передать количество байт (int).
Листинг 1.5, пример:

with open('some_file.txt', mode='r') as f:
    print(f.read(7))

Данный пример выведет первые 7 байт.
Результат:

First l

Важно понимать что .read() начинает читать с того места куда указывает внутренний указатель (узнать это можно с помощью .tell())
Листинг 1.6, пример:

with open('some_file.txt', mode='r') as f:
    print(f.read(7))
    print(f.read(5))

Первый вызов f.read(7) прочитает 7 байт с начала файла (при открытии файла внутренний указатель указывает на нулевой байт, т.е. начало файла). Второй вызов прочитает 5 байт начиная с 8го байта.
Результат:

First l
ine
S

Запись файла .write()

Для того чтобы запись данные в файл надо вызвать метод .write() у объекта файла.
Описание метода:

f.write(data)

Как видим метод write принимает один аргумент — данные, которые вы хотите записать в файл.

Есть 2 основных режима (аргумент mode у функции open) открытия файла на запись:

  1. 'w' — файл открывается на запись, но полностью очищается
  2. 'a' — файл открывается на запись, но данные добавляются в конец файла

Откроем файл на запись и допишем данные в конец файла.
Листинг 1.7, пример использования:

with open('some_file.txt', mode='a') as f:
    f.write('Some new data')

Теперь если вы откроете файл в редакторе (или выведете содержимое командой cat some_file.txt) вы увидите что данные ('Some new data') добавились в конец файла.

Метод .tell

Метод .tell() возвращает текущую позицию в файле. Каждый раз после вызова .read() позиция (указатель) смещается на количество байт, которые мы прочитали.
Листинг 1.8, пример:

with open('some_file.txt', mode='r') as f:
    print(f.read(7))
    print(f.tell())

Результат:

First l
7

Видим что текущая позиция — 7, т.к. мы прочитали первые 7 байт и следующее чтение начнётся именно с этой позиции.

Метод .seek()

Метод .seek() позволяет переместить ‘внутренний указатель’ на любую позицию (например, в начало файла после того как вы его уже прочитали).
Давайте посмотрим на описание методы .seek():

f.seek(offset)

Как видим метод .seek() принимает аргумент offset — это позиция на которую надо сдвинуть ‘внутренний указатель’ (по умолчанию указывается абсолютная позиция в байтах).

Давайте попробуем 2 раза подряд прочитать файл.
Листинг 1.9:

with open('some_file.txt', mode='r') as f:
    print(f.read())
    print(f.read())

Результат выполнения кода:

First line
Second line

Видим что второй раз файл не получилось прочитать. Но как же тогда делать? Не открывать же файл заново. Именно для этого и нужен метод .seek().
Листинг 1.10, пример использования метода .seek():

with open('some_file.txt', mode='r') as f:
    print(f.read())
    f.seek(0)
    print(f.read())

Результат выполнения данного кода:

First line
Second line

First line
Second line

Асинхронная работа с файлами

Все примеры работы с файлами описанные выше являются синхронными, так как Python не предоставляет «из коробки» возможность асинхронной работы с файлами. Исправить данное недоразумение поможет проект aiofile ( https://github.com/mosquito/aiofile ). Данный проект полностью дублирует стандартное файловое api Python, но вместо синхронных операций использует асинхронные. В POSIX операционных системах асинхронная работа реализована через aio.h (с помощью Cython). В non-POSIX операционных системах (например Windows) асинхронная работа реализована с помощью потоков (threads).

Пример асинхронной работы с файлом

Ниже приведён код для асинхронного открытия, записи и чтения файла.
Листинг 1.11 (example_01.py):

import asyncio
from aiofile import AIOFile


async def main():
    async with AIOFile("./example.txt", 'w+') as afp:
        await afp.write('Hello!')
        await afp.fsync()
        print(await afp.read())


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

После запуска данного кода вы увидите на экране текст

Hello!

А в папке с файлом (в который вы сохранили данный код) появится файл example.txt.

Больше примеров вы сможете найти в репозитории проекта aiofile — там есть примеры для чтения файла по строкам, примеры асинхронной работы с CSV файлами и много других полезных примеров.

Заключение

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

Posted in Python, БлогTaggs:
Write a comment