The doorway to file-handling in Python
![]()
open() will open a file and return a file object:
This returns some Beatles lyrics:
If you want to be certain you’re reading the file, use the ‘r’ mode:
In fact open(filename, mode) is the accepted way of coding to avoid confusion if someone else is reading your code, with ‘r’ the default.
Going straight for the file will certainly work if you’re prepared to look after your own code blocks, but it’s normal to use a with statement:
This gives the same result. with will close the file automatically at the end of its block. What if you want to read and write to the existing file? Add a ‘+’ to the mode:
What? No text appears? Well if you check ‘demo’ you’ll see the text is in there. The way python handles file location is to use the idea of a cursor, which stays wherever the file was last accessed for reading or writing. Use ‘tell()’ to find out where your curser is:
I’ve added comments to the code as well just to clarify what’s going on.
What’s the difference between r+ and w+?
So if r+ lets you read and write, and w+ lets you read and write, then what’s the difference? Well, what if ‘demo’ file is missing at the start? r+ will exit with an error. To fix this, change the r+ mode to w+. This will still truncate the file, but will create it as well if it doesn’t exist.
Работа с файлами в Python. Чтение и запись
Файл — это контейнер для хранения данных. Когда мы хотим читать из файла или записывать в него, нам нужно сначала его открыть. После того, как мы закончили чтение/запись, нам нужно закрыть файл, чтобы освободить ресурсы, связанные с ним.
Таким образом, в Python операции с файлами выполняются в следующем порядке:
чтение или запись;
Открыть файл в Python
В Python для открытия файлов используется метод open(). Например, у нас есть файл test.txt со следующим содержимым:

Теперь попробуем открыть этот файл с помощью функции open():
Здесь мы создали файловый объект с именем file1 . Его можно использовать для работы с файлами и каталогами.
По умолчанию файлы открыты в режиме чтения (не могут быть изменены). Вышеприведенный код равнозначен:
Здесь «r» означает, что файл открыт для чтения.
| Режим | Описание |
| r | Открыть файл для чтения. (используется по умолчанию) |
| w | Открыть файл для записи. Создает новый файл, если он не существует, или удаляет содержимое файла, если он существует. |
| x | Открыть файл для эксклюзивного создания. Если файл уже существует, операция завершится неудачно. |
| a | Открыть файл для добавления данных в конец файла без удаления текущего содержимого. Создает новый файл, если он не существует. |
| t | Открыть файл в текстовом режиме. (используется по умолчанию) |
| b | Открыть файл в двоичном режиме. |
| + | Открыть файл для обновления (чтение и запись). |
Вот несколько простых примеров того, как открыть файл в разных режимах:
Чтение файлов в Python
В Python для чтения файлов используется метод read(). Например:
This is a test file.
Hello from the test file.
Обратите внимание на строку:
Здесь file1.read() читает файл test.txt и сохраняет его в переменную read_content .
Закрыть файл в Python
Когда мы закончили выполнять операции с файлом, нам нужно его правильно закрыть. Закрытие файла освобождает ресурсы, которые были задействованы для работы с ним. Это делается с помощью метода close(). Например:
This is a test file.
Hello from the test file
Здесь мы использовали метод close() для закрытия файла. После выполнения операции с файлом мы всегда должны закрывать файл; это важный момент.
Обработка исключений в файлах
Если во время выполнения какой-либо операции с файлом возникает исключение, программа завершает свое выполнение, не закрывая при этом файлы. Одним из решений является использование блока try. finally .
Здесь мы закрыли файл в блоке finally , поскольку блок finally всегда выполняется, то файл будет закрыт, даже если выбросится исключение.
Использование синтаксиса with…open
В Python мы можем использовать синтаксис with. open для автоматического закрытия файла. Например:
Примечание: Поскольку в данном варианте не нужно беспокоиться о закрытии файла, рекомендуется всегда использовать синтаксис with. open .
Запись в файл в Python
При записи в файл необходимо помнить две вещи:
Если мы пытаемся открыть несуществующий файл, создается новый файл.
Если файл уже существует, его содержимое удаляется, а в файл добавляется новое содержимое.
Для того чтобы записать данные в файл в Python, нам нужно открыть его в режиме записи, указав «w» в функции open() в качестве второго аргумента.
Предположим, у нас нет файла с именем test2.txt. Давайте посмотрим, что произойдет, если мы выполним запись в файл test2.txt:
Здесь создается новый файл test2.txt с содержимым, указанным внутри методов write():
Файлы и каталоги в Python
Любая программа в конечном итоге представляет собой обычный набор файлов, сгруппированных по какому-либо признаку по каталогам программы. Поэтому в Python предусмотрен внушительный набор инструментов для работы с файлами и каталогами, которые позволяют выполнять над ними такие операции как создание, удаление, переименование, перемещение, чтение, запись, перезапись и многие другие полезные операции. Но что представляют из себя файлы и каталоги?
(от англ. file) – это именованная область данных на носителе информации.
Имена файлов нужны для того, чтобы точно знать, к какой области данных носителя информации осуществляется запрос. При этом большинство операционных систем в целях однозначности не допускает использование двух файлов с полностью идентичными именами в одном каталоге. Что касается набора символов, которые разрешается использовать для имен файлов, а также максимально допустимой длины имен файлов, то они зависят от используемой файловой системы. Например, Windows допускает использование в имени файла заглавных и строчных букв, цифр, некоторых знаков препинания и пробела, но запрещает использование символов > , , / , \ , | , ? , * , : , » . При этом максимально допустимая длина имен файлов в различных системах обычно не превышает 256 символов.
Чтобы помочь системе определить тип файла и, соответственно, приложение для работы с ним, в имени файла обычно указывается его расширение, которое отделяется от остальной части имени точкой. Примерами расширений файлов могут служить: .txt – обычный текстовый файл, .py – файл с кодом Пайтона , .html – файл, представляющий собой html -документ, .jpg – файл изображения в формате jpg и огромное число других расширений.
Когда файлов становится слишком много, возникает необходимость их упорядочивания и группировки. Для этих целей используются каталоги или директории.
или (от англ. directory) – это специальный объект файловой системы, который используется для упрощения организации файлов. В графическом пользовательском интерфейсе каталоги также называют . В любом случае каталог представляет собой файл, содержащий записи о входящих в него файлах или других каталогах.
Каталог, прямо или косвенно включающий в себя все прочие каталоги и файлы программы, называется . А каталог, в котором находится текущий каталог, называется .
Как было сказано выше, большинство операционных систем не разрешает использование двух файлов с полностью идентичными именами в одном каталоге. В то же время вполне допустимо создавать для одного и того же файла несколько имен при помощи жестких ссылок.
или (от англ. hard link) называют различные имена одного и того же файла, которые могут создаваться в пределах одного физического носителя.
После создания жесткой ссылки сказать где настоящий файл, а где хардлинк невозможно, так как они полностью равноправны. Сама же область данных существует до тех пор, пока не будут удалены полностью все имена. Кроме того, при редактировании файла через одну из ссылок на него, содержимое по другим ссылкам также изменяется.
Как следует из определения, создание жестких ссылок одного и того же файла на разных физических носителях (например, жестких дисках) невозможно. Однако данное ограничение можно обойти при помощи символических ссылок.
или (от англ. symbolic link) – это специальный файл в файловой системе, содержащий в себе ссылку на другой файл или директорию, в том числе, и расположенный на другом физическом носителе.
Символическая ссылка занимает ровно столько места в файловой системе, сколько требуется для записи её содержимого, которое представляет собой строку, содержащую путь к определенному файлу или каталогу. Если символьная ссылка указывает на файл, который не существует, ее называют . При попытке обращения к файлу посредством битой ссылки обычно выводится соответствующее предупреждение.
Рассмотрим основные встроенные возможности языка Python для работы с файлами и каталогами.
Функция open: запись и чтение файлов
Редактирование содержимого файла подразумевает осуществление таких операций, как открытие и закрытие файла, чтение и запись, получение текущего значения файлового указателя и его перемещение в соответствии с заданными параметрами, сброс файлового буфера и некоторые другие операции. При этом, используя для редактирования соответствующие функции Python , нужно иметь также и некоторое представление о понятиях, которые имеют непосредственное отношение к работе с файлами. Приведем краткое описание наиболее важных из них.
- (от англ. file descriptor) – неотрицательное целое число, которое операционная система возвращает при открытии файла (в случае, если это возможно) и с помощью которого выполняются все остальные файловые операции. По завершении операций и закрытии файла дескриптор теряет смысл.
- – число, указывающее величину смещения относительно нулевого байта в файле. Обычно по этому адресу осуществляется чтение/запись, если конечно вызов операции чтения/записи не предусматривает указание адреса. При выполнении операций чтения/записи файловый указатель смещается на число прочитанных/записанных байт. В результате последовательный вызов операций чтения позволяет прочитать весь файл не обращая внимания на его размер.
- – специально выделенный участок памяти (буфер), в котором операционная система осуществляет кэширование файловых операций. При закрытии файла буфер сбрасывается.
- – режим устанавливающий разрешения на чтение и запись файла при его открытии.
Для чтения и записи файлов в Python предназначена встроенная функция open(file, mode=’r’, buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None) , которая возвращает специальный итерируемый файловый объект, связанный с целевым файлом. Если файл не может быть открыт, бросается исключение OSError . Обязательным является только первый параметр, в качестве которого необходимо передавать строку с путем к файлу. Все остальные параметры необязательны. Пройдемся по ним.
- file – строка, содержащая абсолютное или относительное значение пути к файлу.
- mode=’r’ – строка с индикатором режима, в котором следует открыть файл:
- ‘r’ – открыть файл на чтение (значение по умолчанию).
- ‘w’ – открыть файл на запись (содержимое файла удаляется, а если его нет, то создается новый).
- ‘x’ – создать файл и открыть его на запись либо сгенерировать исключение FileExistsError , если файл с таким именем уже существует.
- ‘a’ – открыть файл на дозапись (содержимое файла не удаляется, а запись новой информации осуществляется в конец файла).
- ‘b’ – открыть файл в бинарном режиме; используется как дополнительный флаг, например, ‘rb’ , ‘wb’ или ‘ab’ .
- ‘t’ – открыть файл в текстовом режиме; используется как дополнительный флаг по умолчанию.
- ‘+’ – открыть файл на чтение и запись одновременно; используется как дополнительный флаг:
- ‘r+’ – открыть существующий файл на чтение и запись, поместив файловый указатель в начало файла;
- ‘w+’ – открыть существующий файл на запись и чтение, удалив содержимое и поместив файловый указатель в начало файла, либо создать новый файл в случае его отсутствия;
- ‘x+’ – создать файл и открыть его на запись и чтение, поместив файловый указатель в начало файла, либо сгенерировать исключение FileExistsError , если файл с таким именем уже существует;
- ‘a+’ – открыть существующий файл на дозапись и чтение, не удаляя содержимое и поместив файловый указатель в конец файла, либо создать новый файл в случае его отсутствия (при чтении следует не забывать перемещать файловый указатель в нужную позицию файла);
- ‘rb+’ или ‘r+b’ – открыть существующий файл на чтение и запись в бинарном режиме, поместив файловый указатель в начало файла;
- ‘wb+’ или ‘w+b’ – открыть существующий файл на запись и чтение в бинарном режиме, удалив содержимое и поместив файловый указатель в начало файла, либо создать новый файл в случае его отсутствия;
- ‘xb+’ или ‘x+b’ – создать файл и открыть его на запись и чтение в бинарном режиме, поместив файловый указатель в начало файла, либо сгенерировать исключение FileExistsError , если файл с таким именем уже существует;
- ‘ab+’ или ‘a+b’ – открыть существующий файл на дозапись и чтение в бинарном режиме, не удаляя содержимое и поместив файловый указатель в конец файла, либо создать новый файл в случае его отсутствия (при чтении следует не забывать перемещать файловый указатель в нужную позицию файла).
- 0 – отключить буферизацию (только для бинарного режима).
- 1 – построчная буферизация (только для текстового режима).
- n > 1 – размер буфера в байтах.
- -1 – значение по умолчанию: для текстовых файлов, используется построчная буферизация, а двоичные файлы буферизируются кусками фиксированного размера. Для многих систем буфер равен 4096 или 8192 байт. Если же размер буфера определить не удается, используется io.DEFAULT_BUFFER_SIZE .
Стоит заметить, что использовать все параметры функции open() вовсе необязательно, т.к. в большинстве случаев для открытия и работы с файлами достаточно указать путь к файлу, режим работы и кодировку (см. пример №1 ).
Пример №1. Чтение и запись файлов в Python (часть 1).
Как видим, после получения файлового объекта, возвращаемого функцией open() , редактирование данных в открытом файле производится с помощью специального предназначенного для этого набора методов. Перечислим некоторые из них.
- read([size]) – считывает из файла не более size байтов. Если же конец файла EOF достигается до получения указанного размера, метод считывает только доступные байты. В текстовом режиме возвращается строка, в бинарном – байтовый объект.
- readline([size]) – читает и затем возвращает одну целую строку из файла, включая конечный символ \n (если файл открыт в бинарном режиме, метод возвращает байтовый объект). Если указать неотрицательный аргумент size , строка будет считываться частями по size байтов до тех пор, пока не будет достигнут символ новой строки \n . При отрицательном значении size строка будет считываться полностью. В любом случае при достижении конца файла EOF метод вернет пустую строку.
- readlines(sizehint) – возвращает список строк или байтовых объектов файла в зависимости от режима доступа к файлу, включая конечные символы \n строк. Опять же, при достижении конца файла EOF возвращается пустая строка. При наличии необязательного аргумента sizehint читаются целые строки, составляющие приблизительно sizehint байт (округление производится до внутреннего размера буфера).
- write(str) – записывает в файл строку str и возвращает количество записанных байт в виде целого числа. Имейте в виду, что из-за буферизации строка может не отображаться в файле до тех пор, пока не будет вызван метод flush() или close() . Поскольку различные операционные системы имеют собственные соглашения по обозначению конца строки, следует быть внимательным при записи данных в текстовый файл, правильно устанавливая символы конца строки в соответствии с операционной системой, под которой работает скрипт: \n для Unix/Linux , \r\n для Windows и \r для Macintosh .
- writelines(seq) – записывает в файл последовательность строк seq . Последовательностью может быть любой итерируемый объект, содержащий строки в качестве элементов. Следует помнить, что разделители строк при необходимости должны добавляться вручную.
- truncate([size]) – усекает размер файла в байтах по текущему указателю чтения/записи и возвращает size . Если необязательный аргумент size указан, файл усекается до этого размера. Метод не будет работать, если файл открыт в режиме только чтения.
- seek(offset, [whence]) – устанавливает файловый указатель чтения/записи в требуемую позицию offset , которая по умолчанию отсчитывается в байтах от начала файла. Необязательный параметр whence может иметь три значения:
- 0 – указатель будет смещен на offset относительно начала файла (используется по умолчанию);
- 1 – указатель будет смещен на offset относительно текущей позиции указателя;
- 2 – указатель будет смещен на offset относительно конца файла.
Следует всегда закрывать открытый файл после окончания работы с ним, если только файл не был открыт с помощью менеджера контекста with/as , т.к. в этом случае закрытие файла осуществляется в автоматическом режиме (см. пример №2 ).
Пример №2. Чтение и запись файлов в Python (часть 2).
Остальные методы для работы с потоками можно посмотреть в подразделе «io — Core tools for working with streams» стандартной библиотеки.
Стоит добавить, что после открытия текстового файла в соответствующем режиме, запись в файл можно осуществить и при помощи обычной функции print() , передав ей полученный файловый объект в виде значения именованного аргумента file (см. пример №3 ).
Пример №3. Чтение и запись файлов в Python (часть 3).
Модуль pickle: сериализация объектов
Для сериализации и десериализации объектов в Python предназначен модуль pickle , расположенный в подразделе «pickle — Python object serialization» стандартной библиотеки. Он позволяет преобразовывать объекты как в поток байтов (сериализация), так и обратно из байтового состояния в объекты (десериализация). А поскольку поток байтов можно легко записывать в файл, данный модуль широко используется для долговременного хранения и последующей загрузки различных сложных python -объектов. Перечислим основные методы, предоставляемые данным модулем.
- pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None) – сериализует и записывает объект obj в файловый объект file , возвращая затем строку байтов (т.е. pickle.dumps() ). Необязательные аргументы fix_imports , encoding и errors используются для управления поддержкой совместимости потока pickle , генерируемого Python 2 . Нам они не понадобятся, т.к. мы работаем в Python 3 .
- pickle.load(file, *, fix_imports=True, encoding=»ASCII», errors=»strict») – десериализует объект из файлового объекта file и затем возвращает его.
- pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None) – сериализует объект (т.е. преобразует в двоичное представление) и затем возвращает его.
- pickle.loads(bytes_object, *, fix_imports=True, encoding=»ASCII», errors=»strict») – десериализует объект из двоичного представления и затем возвращает его.
Посмотрим, как эти методы работают на практике (см. пример №4 ).
Пример №4. Использование модуля pickle (часть 1).
Как видим, благодаря модулю pickle мы с легкостью записали наш словарь в файл, затем извлекли его для изменения и записали обратно. Т.е. по сути мы создали простейшую базу данных для длительного хранения наших объектов. Конечно, работать с объемной базой данных таким образом вряд ли получится, ведь даже для малейших изменений придется читать и перезаписывать весь файл целиком. Однако никто не запрещает, например, создать для каждой записи свой файл и при необходимости извлекать данные по отдельности (см. пример №5 ).
Пример №5. Использование модуля pickle (часть 2).
При желании можно было бы оформить обращение к записям нашей базы данных в виде функций или вообще создать отдельный класс для работы с ней. Главное здесь помнить о том, что не стоит загружать с помощью модуля pickle файлы из ненадёжных источников, т.к. это может привести к непредвиденным и печальным последствиям.
Модуль shelve: key/value хранилище объектов
Если к сохраненным в файлах записям необходим доступ по ключу, вместо модуля pickle удобнее использовать более высокоуровневый инструмент стандартной библиотеки в виде модуля shelve (см. подраздел «shelve — Python object persistence»). Данный модуль реализует постоянное хранилище для произвольных python -объектов, значения которого можно извлекать, используя синтаксис и методы обычного словаря со строковыми ключами.
Осуществляется создание либо открытие такого хранилища с помощью метода shelve.open(filename, flag=’c’, protocol=None, writeback=False) , где
- filename – путь к создаваемому хранилищу и его имя, но без какого-либо расширения. При этом целевой каталог хранилища должен уже существовать, иначе будет получено исключение.
- flag – режим открытия хранилища:
- ‘c’ – хранилище открывается для чтения и записи (используется по умолчанию). Если такого хранилища не существует, то оно вначале создается.
- ‘r’ – хранилище открывается для чтения.
- ‘w’ – хранилище открывается для записи.
- ‘n’ – хранилище открывается для перезаписи. Если такого хранилища не существует, то оно вначале создается.
Результатом вызова shelve.open() является специальный объект для работы с открытым хранилищем, поддерживающий синтаксис и методы обычных словарей и обладающий двумя собственными методами:
- sync() – очищает кеш, записывая все записи из него на диск и синхронизируя хранилище, если хранилище было открыто с флагом writeback=True ;
- close() – синхронизирует и закрывает хранилище или возбуждает ValueError , если оно уже было закрыто.
Рассмотрим использование возможностей модуля shelve для создания постоянного хранилища данных, с последующим добавлением в него новых данных или редактирования/удаления уже существующих (см. пример №6 ).
Пример №6. Использование модуля shelve (часть 1).
Как видим, в простейшем случае для создания хранилища (или открытия уже существующего) нужно передать методу shelve.open() путь к создаваемому хранилищу и его имя, но без какого-либо расширения. В результате в целевом каталоге (либо в каталоге скрипта) интерпретатором будет создано три служебных файла с указанным именем и расширениями .bak , .dat и .dir . При этом целевой каталог хранилища должен существовать еще до начала операции, иначе будет получено исключение. Именно поэтому в нашем примере мы предварительно создали в директории скрипта каталог для хранилища db_devices и только затем указали его в качестве целевого каталога в вызове метода shelve.open() . В результате интерпретатор создал в нем три служебных файла хранилища: db_devices.bak , db_devices.dat и db_devices.dir .
После создания и открытия хранилища можно начинать записывать в него данные, используя для этого синтаксис обычного словаря со строковыми ключами. Здесь главное помнить, что по умолчанию writeback=False , т.е. кеширование данных в памяти, не используется. Поэтому для последующего редактирования изменяемых объектов хранилища их сперва нужно извлечь по ключу, сохранить копию во временной переменной, выполнить над переменной все необходимые операции и в конце записать измененный объект обратно в хранилище (удалив по необходимости и временную копию). В нашем случае последовательность инструкций была следующая: temp_mouse = db_devices[‘mouse’] (мы извлекли из хранилища целевой словарь и присвоили его переменной), temp_mouse[‘кол-во’] = 5 (внесли необходимые изменения в словарь), db_devices[‘mouse’] = temp_mouse (сохранили изменения в хранилище).
Помимо изменения записей открытого хранилища для него доступны также операции по добавлению новых записей и удалению уже существующих. Главное не забывать после завершения всех работ закрывать открытое хранилище с помощью метода close() . Опять же, при использовании менеджера контекста with/as использовать данный метод нет нужды, т.к. при выходе за область его видимости синхронизация с хранилищем и его закрытие будут произведены автоматически.
Далее. Использование параметра обратной записи writeback со значением True может быть весьма удобным, если заранее известно, что количество одновременных запросов к различным записям хранилища будет невелико, как и объем хранимых в них данных. В этом случае все результаты операций будут кешироваться в памяти, что несколько замедлит процесс закрытия хранилища из-за одновременного перемещения данных кеша на диск, но зато хранимые объекты станут доступны для непосредственной обработки с помощью имеющихся у них методов без необходимости создания каких-либо промежуточных копий объектов (см. пример №7 ).
Пример №7. Использование модуля shelve (часть 2).
В общем случае модуль shelve позволяет хранить в файлах не только словари, но и другие сложные объекты, сериализация которых поддерживается модулем pickle (см. пример №8 ).
Пример №8. Использование модуля shelve (часть 3).
Опять же, не стоит без проверки загружать с помощью модулей pickle и shelve файлы из ненадёжных источников, т.к. это может привести к непредвиденным и печальным последствиям в случае передачи злонамеренного кода.
Модуль pathlib: работа с путями
Модуль pathlib представляет собой высокоуровневый инструмент для манипулирования путями файловой системы, по сути объединяя в себе возможности таких модулей, как os , os.path или glob . Ознакомится с документацией по модулю можно в справочнике стандартной библиотеки в подразделе «pathlib — Object-oriented filesystem paths». Здесь же мы рассмотрим наиболее востребованные кроссплатформенные свойства и методы для работы с путями, каталогами и файлами, имеющиеся у класса PurePath и его подкласса Path модуля pathlib .
Объекты pathlib.PurePath() обеспечивают операции обработки пути, которые фактически не обращаются к файловой системе. Поэтому их можно использовать для манипулирования путями Windows на машине Unix или наоборот, не волнуясь при этом за правильную обработку пути. В тоже время подкласс pathlib.Path() представляет пути файловой системы, которые работают с системными вызовами. При создании экземпляра класса pathlib.Path() в зависимости от операционной системы на которой выполняется код, происходит автоматический вызов либо его подкласса pathlib.PosixPath (работа с путями файловой системы, отличной от Windows ), либо pathlib.WindowsPath (работа с путями Windows ). Перечислим основные методы этих классов по работе с путями и рассмотрим конкретные примеры использования предоставляемых возможностей в исходном коде.
- Path.cwd() – возвращает объект пути, представляющий текущий рабочий каталог (похоже на os.getcwd() ).
- Path.home() – возвращает объект пути, представляющий домашний каталог пользователя (похоже на os.path.expanduser() ).
- Path(path).expanduser() – возвращает объект абсолютного пути path , в котором пользовательские конструкции
user в начале пути заменяются на домашний каталог пользователя (похоже на os.path.expanduser() ). Если расширение пути завершается неудачно или путь не начинается с тильды
Пример №9. Использование класса pathlib.Path (часть 1).
- Path(path).exists() – проверяет существование пути path файловой системы, возвращая True или False (похоже на os.path.exists() ). Если путь указывает на символическую ссылку, метод проверяет, указывает ли она на существующий файл или каталог.
- Path(path).is_dir() – возвращает True , если путь path указывает на каталог или символическую ссылку, указывающую на каталог (похоже на os.path.isdir(path) ). Если путь указывает на файл другого типа, вообще не существует или является неработающей символической ссылкой, метод возвращает False . Также метод может вернуть False , если доступ к директории или символической ссылке, указывающей на директорию, отсутствует.
- Path(path).is_file() – все тоже, что и для метода выше, только для файлов (см. пример №10 ). Метод похож на os.path.isfile(path) .
Пример №10. Использование класса pathlib.Path (часть 2).
- Path(path).mkdir(mode=0o777, parents=False, exist_ok=False) – создает по указанному пути path новый каталог (похоже на os.mkdir() ). Метод принимает следующие аргументы:
- mode=0o777 – режим доступа к директории.
- parents=False – по умолчанию при наличии в цепочке отсутствующих каталогов будет вызвано исключение FileNotFoundError . Если необходимо, чтобы отсутствующие каталоги нового пути были созданы, следует указывать parents=True .
- exist_ok=False – по умолчанию в случае существования целевого каталога будет вызвано исключение FileExistsError . При использовании exist_ok=True исключения игнорируются.
Пример №11. Использование класса pathlib.Path (часть 3).
- Path(path).rename(target) – переименовывает/перемещает файл или конечный каталог пути path в target (похоже на os.rename() ). В качестве target разрешается передавать как строку, так и объект пути. Путь path должен существовать, иначе будет брошено исключение. Если путь target уже существует, то в Windows будет брошено исключение, а в Unix путь (файл) будет перезаписан (см. пример №12 ).
- Path(path).replace(target) – заменяет существующий файл или конечный каталог пути path на target (похоже на os.replace() ). В качестве target разрешается передавать как строку, так и объект пути. Путь path должен существовать, иначе будет брошено исключение. Если путь target уже существует, то в Windows будет брошено исключение, а в Unix путь (файл) будет перезаписан. Основное отличие этого метода от Path(path).rename(target) заключается в том, что в ходе замены (переименования) файла данные в нем будут безвозвратно удалены.
Пример №12. Использование класса pathlib.Path (часть 4).
- Path(path).open(mode=’r’, buffering=-1, encoding=None, errors=None, newline=None) – открывает файл, на который указывает путь path , и возвращает соответствующий файловый объект для доступа к нему, как это делает встроенная функция open().
- Path(path).write_text(data, encoding=None, errors=None, newline=None) – открывает файл для записи в текстовом режиме, записывает в него данные data и закрывает его, возвращая количество записанных байт. Если файл с таким именем уже существует, он перезаписывается. Необязательные параметры имеют тот же смысл, что и для встроенной функции open() .
- Path(path).read_text(encoding=None, errors=None) – открывает, читает и затем закрывает текстовый файл, возвращая прочитанную строку.
- Path(path).write_bytes(data) – открывает файл для записи в бинарном режиме, записывает в него данные data и закрывает его, возвращая количество записанных байт. Если файл с таким именем уже существует, он перезаписывается.
- Path(path).read_bytes() – открывает, читает и затем закрывает двоичный файл, возвращая байтовый объект (см. пример №13 ).
Пример №13. Использование класса pathlib.Path (часть 5).
- Path(path).glob(pattern) – возвращает список всех файлов, соответствующих заданному шаблону pattern и расположенных в каталоге, указанном в пути path . Начиная с Python 3.11 метод возвращает только каталоги, если шаблон pattern заканчивается разделителем компонентов пути ( os.sep или os.altsep ). Если в шаблоне использовать комбинацию ** , то будет осуществляться рекурсивный обход в глубину каталога, указанного в пути path , и всех его подкаталогов. Это удобно, но в больших деревьях каталогов может занимать слишком много времени.
- Path(path).rglob(pattern) – производит рекурсивный поиск файлов аналогично предыдущему методу за счет автоматического добавления **/ в начале шаблона pattern .
- Path(path).iterdir() – возвращает итератор объектов в каталоге, на который указывает путь path (см. пример №14 ).
Пример №14. Использование класса pathlib.Path (часть 6).
Модуль shutil: операции над файлами и каталогами
Модуль shutil содержит набор высокоуровневых функций для обработки файлов и каталогов, позволяющих, например, копировать, перемещать, удалять и даже архивировать их. Опять же, ознакомится с документацией по модулю можно в справочнике стандартной библиотеки в подразделе «shutil — High-level file operations». Здесь же мы рассмотрим лишь наиболее востребованные кросплатформенные свойства и методы для операций над файлами и каталогами.
- shutil.copyfileobj(fsrc, fdst[, length]) – копирует содержимое файлового объекта fsrc в другой файловый объект fdst . Необязательный параметр length — размер буфера при копировании (используется для предотвращения чтения в память огромных файлов целиком). Следует помнить, что копирование осуществляется с текущей позиции указателя в fsrc , а не с начала файла.
- shutil.copyfile(src, dst, follow_symlinks=True) – копирует содержимое файла src без метаданных в файл dst и возвращает dst . Аргументы src и dst должны быть строками, содержащими пути к файлам. При чем dst должен быть полным именем файла. Если указать существующий файл dst , он будет перезаписан. Если src и dst представляют собой один и тот же файл, будет брошено исключение shutil.SameFileError . Если аргумент follow_symlinks=False , а src является ссылкой на файл, то будет создана новая символическая ссылка вместо копирования файла, на который эта символическая ссылка указывает.
- shutil.copy(src, dst, follow_symlinks=True) – копирует содержимое файла src вместе с правами доступа в файл или каталог dst и возвращает путь к местонахождению нового скопированного файла. Если dst является каталогом, файл будет скопирован со своим прежним именем. Если аргумент follow_symlinks=False , а src – это ссылка, то dst также будет ссылкой. Если же follow_symlinks=True , а src – это ссылка, то dst будет копией файла, на который ссылается src .
- shutil.copy2(src, dst, follow_symlinks=True) – работает как copy() , но пытается копировать вообще все метаданные.
- shutil.copymode(src, dst, follow_symlinks=True) – копирует права доступа из src в dst . Содержимое файла, владелец и группа не затрагиваются.
- shutil.copystat(src, dst, follow_symlinks=True) – копирует права доступа, время последнего доступа и последнего изменения, а также флаги src в dst . Содержимое файла, владелец и группа не затрагиваются.
- shutil.chown(path, user=None, group=None) – меняет владельца и/или группу у файла или каталога.
- shutil.ignore_patterns(*patterns) – создает функцию, которая позволяет выборочно копировать файлы из каталогов, игнорируя файлы и каталоги в соответствии с одним из предоставленных шаблонов *patterns типа glob.glob() . Созданная функция может быть использована в качестве значения аргумента ignore для copytree() .
- shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False, dirs_exist_ok=False) – рекурсивно копирует дерево каталогов src в каталог dst и возвращает каталог назначения. Аргумент dirs_exist_ok указывает, следует ли вызвать исключение в случае, если целевой каталог dst или какой-либо отсутствующий родительский каталог уже существует. Права и времена у каталогов копируются с помощью функции copystat() , а файлы по умолчанию копируются с помощью функции copy2() , хотя в аргумент copy_function разрешается передавать любую функцию, поддерживающую такую же сигнатуру, например shutil.copy() . По умолчанию, когда symlinks=False , копируются как содержимое, так и метаданные файлов, на которые указывали ссылки. При этом, если файл, на который указывает ссылка, не существует, в список ошибок в исключении shutil.Error в конце копирования будет добавлено исключение, скрыть которое можно путем установки флага ignore_dangling_symlinks=True . Если аргумент symlinks=True , ссылки в дереве src станут ссылками в dst , а метаданные будут скопированы настолько, насколько это возможно. Если значение аргумента ignore не равно None , то это должен быть объект функции, принимающей в качестве аргументов имя целевого каталога dst и список его содержимого, возвращаемый функцией os.listdir() . Поскольку copytree() вызывается рекурсивно, функция в ignore будет вызываться один раз для каждого вложенного копируемого каталога. Кроме того, переданная в ignore функция должна возвращать последовательность имен каталогов и файлов относительно текущего каталога, то есть подмножества элементов во втором аргументе. Эти имена будут игнорироваться в процессе копирования.
- shutil.move(src, dst, copy_function=copy2) – рекурсивно перемещает файл или каталог из src в другое место dst и возвращает место назначения dst . Если dst является существующим каталогом, то src перемещается внутрь каталога. Если же цель dst существует, но не является каталогом, то она может быть перезаписана.
- shutil.rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None) – рекурсивно удаляет все дерево каталогов. При этом путь path должен указывать именно на каталог, а не символическую ссылку на каталог. Если указать ignore_errors=True , то возникшие в результате неудачного удаления ошибки будут игнорироваться. По умолчанию, когда ignore_errors=False , такие ошибки вызывают исключения или обрабатываются путем вызова обработчика, если он используется в onerror .
- shutil.which(cmd, mode=os.F_OK | os.X_OK, path=None) – возвращает путь к исполняемому файлу, который будет запущен при вызове командного файла cmd (путь к нему передается в виде строки). Если никакая команда не будет вызвана, функция вернет None . Аргумент mode – это права доступа, требующиеся от файла. По умолчанию проверяется только существование файла и является ли он исполняемым.
- shutil.disk_usage(path) – возвращает статистику использования диска по указанному пути в виде именованного кортежа с атрибутами total , used и free , представляющих осответственно общий объем диска, используемый объем и объем свободного пространства в байтах. Путь path может быть файлом или каталогом (см. пример №15 ).
Пример №15. Использование модуля shutil (часть 1).
Помимо функций для работы с обычными файлами и каталогами модуль shutil предоставляет также несколько высокоуровневых функций, основанных на возможностях модулей zipfile и tarfile, для создания и чтения архивированных и сжатых файлов. Пробежимся по ним.
- shutil.make_archive(base_name, format[, root_dir[, base_dir[, verbose[, dry_run[, owner[, group[, logger]]]]]]]) – создает архивный файл, например zip или tar и возвращает его имя. Первые два аргумента обязательны для передачи, остальные могут быть опущены:
- base_name – путь к создаваемому архиву с указанием в конце пути имени файла архива без расширения, т.к. оно зависит от выбранного формата (например, ‘./dir_1/dir_2’ ).
- format – формат создаваемого архива: ‘zip’ , ‘tar’ или ‘gztar’ , если доступен модуль zlib; bztar , если доступен модуль bz2; xztar , если доступен модуль lzma.
- root_dir – корневой каталог, относительно которого будет строиться путь к архивируемому файлу или каталогу base_dir (по умолчанию используется текущий каталог).
- base_dir – путь к существующему файлу или каталогу, который требуется заархивировать, отсчитываемый относительно корневого каталога root_dir ; если путь не указывается, то в архив будет помещено все содержимое каталога root_dir ; если указать неверный путь, будет брошено соответствующее исключение.
- verbose – устаревший, больше не используется и не рекомендуется.
- dry_run – если данный аргумент имеет значение True , архив не создается, но выполняемые операции записываются в журнал.
- owner – используется при создании архива tar . По умолчанию используется текущий владелец.
- group – используется при создании архива tar . По умолчанию используется текущая группа.
- logger – данный аргумент должен быть объектом, совместимым с PEP 282 , обычно это экземпляр logging.Logger.
Пример №16. Использование модуля shutil (часть 2).
Краткие итоги параграфа
- Файл – это именованная область данных на носителе информации. При этом большинство операционных систем в целях однозначности не допускает использование двух файлов с полностью идентичными именами в одном каталоге.
- Чтобы помочь системе определить тип файла и, соответственно, приложение для работы с ним, в имени файла обычно указывается его расширение, которое отделяется от остальной части имени точкой. Примерами расширений файлов могут служить .txt – обычный текстовый файл, .py – файл с кодом Пайтона и огромное число других расширений.
- Когда файлов становится слишком много, возникает необходимость их упорядочивания и группировки. Для этих целей используются каталоги или директории, которые представляют собой специальные объекты файловой системы, используемые для упрощения организации файлов. В графическом пользовательском интерфейсе каталоги также называют папками. В любом случае каталоги представляет собой файлы, содержащие записи о входящих в них файлах или других каталогах. При этом каталог, прямо или косвенно включающий в себя все прочие каталоги и файлы программы, называют корневым. А каталог, в котором находится текущий каталог, называют родительским каталогом.
- Для чтения и записи файлов в Python предназначена встроенная функция open() , которая возвращает специальный итерируемый файловый объект, связанный с целевым файлом и обладающий набором методов для чтения, записи и редактирования открытого файла. Сюда относятся, например, методы: read() (читает заданное количество байт из файла), readline() (чтение одной строки), readlines() (читает файл в список строк), write() (записывает строку в файл), writelines() (записывает в файл переданную последовательность строк), close() (закрывает файл).
- Для сериализации и десериализации объектов в Python предназначен модуль pickle стандартной библиотеки. Он позволяет преобразовывать объекты как в поток байтов (сериализация), так и обратно из байтового состояния в объекты (десериализация). А поскольку поток байтов можно легко записывать в файл, данный модуль широко используется для долговременного хранения и последующей загрузки различных сложных python -объектов. Запись объектов в файл осуществляется с помощью функции pickle.dump() , а чтение из файла – pickle.load() .
- Если к сохраненным в файлах записям необходим доступ по ключу, вместо модуля pickle удобнее использовать более высокоуровневый инструмент стандартной библиотеки в виде модуля shelve . Данный модуль реализует постоянное хранилище для произвольных python -объектов, значения которого можно извлекать, используя синтаксис и методы обычного словаря со строковыми ключами. Осуществляется открытие такого хранилища с помощью метода shelve.open() .
- Для манипулирования путями файловой системы предназначен модуль pathlib , который представляет собой высокоуровневый инструмент объединяющий в себе возможности таких модулей, как os , os.path или glob . С его помощью, например, легко определять текущий рабочий каталог ( Path.cwd() ), проверять является путь каталогом ( Path(path).is_dir() ), файлом ( Path(path).is_file() ) и существует ли он вообще ( Path(path).exists() ), создавать директории ( Path(path).mkdir() ) и файлы ( Path(path).touch() ), а также удалять их ( Path(path).rmdir() и Path(path).unlink() ), открывать файлы для чтения и записи ( Path(path).open() ), осуществлять поиск каталогов и файлов по заданному шаблону ( Path(path).glob(pattern) ) и многое другое.
- Также нами был рассмотрен модуль shutil , содержащий набор высокоуровневых функций для обработки файлов и каталогов. В частности модуль дает возможность копировать содержимое файлов ( shutil.copyfileobj() и shutil.copyfile() ), копировать сами файлы и каталоги ( shutil.copy() и shutil.copytree() ), перемещать их ( shutil.move() ), удалять целые деревья каталогов вместе с файлами ( shutil.rmtree() ), а также архивировать их ( shutil.make_archive() и shutil.unpack_archive() ) и т.д.
Вопросы и задания для самоконтроля
1. Что такое файл? Для чего нужны расширения файлов? Показать решение.
Ответ. Файл – это именованная область данных на носителе информации. Имена файлов нужны для того, чтобы точно знать, к какой области данных носителя информации осуществляется запрос. Что касается расширения файла, то оно указывается после точки и призвано помочь системе определить тип файла, а значит и приложение для работы с ним.
2. Для чего нужны каталоги? Какой каталог приложения называют корневым? Какой каталог по отношению к данному является родительским? Показать решение.
Ответ. Каталоги нужны для создания упорядоченной структуры файлов в файловой системе и, в частности, в многофайловой программе. Каталог, прямо или косвенно включающий в себя все прочие каталоги и файлы программы, называется корневым. Родительским называется каталог, в котором находится текущий каталог.
3. Опишите режимы открытия файлов с помощью встроенной функции open() . Показать решение.
Ответ. Режим открытия файла задается аргументом mode , который в качестве строки может принимать следующие значения:
- ‘r’ – открыть файл на чтение (значение по умолчанию);
- ‘w’ – открыть файл на запись (содержимое файла удаляется, а если его нет, то создается новый);
- ‘x’ – создать файл и открыть его на запись либо сгенерировать исключение FileExistsError , если файл с таким именем уже существует;
- ‘a’ – открыть файл на дозапись (содержимое файла не удаляется, а запись новой информации осуществляется в конец файла);
- ‘b’ – открыть файл в бинарном режиме; используется как дополнительный флаг, например, ‘rb’ , ‘wb’ или ‘ab’ ;
- ‘t’ – открыть файл в текстовом режиме; используется как дополнительный флаг по умолчанию;
- ‘+’ – открыть файл на чтение и запись одновременно; используется как дополнительный флаг, например, ‘r+’ или ‘w+’ (файловый указатель помещается в начало файла, если он существует, либо создается новый файл для чтения и записи), ‘a+’ (файловый указатель помещается в конец файла, если он существует, либо создается новый файл для чтения и дозаписи), ‘rb+’ , ‘wb+’ или ‘ab+’ .
4. Как с помощью встроенной функции open() прочитать небольшой текстовый файл целиком, только первую строку? Показать решение.
Ответ. Необходимо открыть файл в режиме чтения с помощью встроенной функции open() , получив соответствующий файловый объект, после чего использовать метод read() этого файлового объекта для чтения файла целиком или метод readline() для чтения первой строки. В конце нужно не забыть закрыть файл с помощью метода close() .
5. Как с помощью встроенной функции open() дописать строку в конец файла? Показать решение.
Ответ. Необходимо воспользоваться встроенной функцией open() в режиме дозаписи ‘a’ , получив соответствующий файловый объект, после чего использовать метод write() этого файлового объекта для дозаписи в конец файла требуемой строки. После завершения записи следует закрыть файл с помощью метода close() .
6. Перепишите представленный код с использованием менеджера контекста. Показать решение.