Перейти к содержанию

Открытие и создание файла

Чтобы открыть файл надо воспользоваться функцией open. Синтаксис функции немного непривычный и не совсем в python-стиле, но зато он практически такой же во всех языках программирования.

open('<путь>', '<режим>')

Параметры функции:

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

Возможные режимы складываются из комбинаций букв:

  • rread, читать
  • wwrite, писать
  • x — exclusive, эксклюзивная запись, если файл уже существует, то вернется ошибка
  • bbinary, бинарный режим записи
  • ttext, текстовый, этот режим по умолчанию
  • aappend, дописывать в конец
  • + — расширяет режим позволяя обновлять существующий файл, подходит и для чтения и для записи одновременно, открытие файла с этим режимом не удаляет старое содержимое

Вот расшифровка сочетаний режимов открытия файлов и их значений:

Режим Значение
r, rt Открыть в текстовом режиме только для чтения. Указатель в начале файла
rb Открыть для чтения в двоичном формате. Указатель в начале файла
r+, rt+ Открыть в текстовом режиме для чтения и записи. Указатель в начале файла
rb+ Открыть для чтения и записи в двоичном формате. Указатель в начале файла
w, wt Открыть в текстовом режиме только для записи. Указатель в начале файла. Удаляет старое содержимое и создает новый файл
wb Открыть для записи в двоичном формате. Указатель в начале файла. Удаляет старое содержимое и создает новый файл
w+, wt+ Открыть в текстовом режиме для чтения и записи. Указатель в начале файла.
wb+ Открыть для чтения и записи в двоичном формате. Указатель в начале файла.
x, xt Эксклюзивно создать файл в текстовом режиме для записи. Если файл с таким именем существует, то вызовет исключение FileExistsError
xb Эксклюзивно создать файл для записи в двоичном формате. Если файл с таким именем существует, то вызовет исключение FileExistsError
a, at Открыть в текстовом режиме для добавления информации в файл. Указатель в конце файла. Создает новый файл, если такового не существовало
ab Открыть для добавления в двоичном формате. Указатель в конце файла. Создает новый файл, если такового не существовало
a+, at+ Открыть в текстовом режиме для добавления и чтения. Указатель в конце файла. Создает новый файл, если такового не существовало
ab+ Открыть для добавления и чтения в двоичном формате. Указатель в конце файла. Создает новый файл, если такового не существовало

После выполнения функция создает объект ввода-вывода, который взаимодействует с файловым хендлером операционной системы. Мы работаем с ним как с объектом Python у которого есть свои методы и свойства.

Свойства файлового объекта

Давайте откроем свой первый файл и посмотрим на полученный объект:

>>> f = open("test.txt", "wt")
>>> type(f)
<class '_io.TextIOWrapper'>
>>> dir(f)
['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_finalizing', 'buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 'read', 'readable', 'readline', 'readlines', 'reconfigure', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'write_through', 'writelines']
>>> f.closed
False
>>> f.close()
>>> f.closed
True

У объекта файла есть множество методов и свойств. Самое главное, что надо знать, то, что у файлового объекта есть состояние, и оно проверяется с помощью флага f.closed, файл считается открытым до тех пор, пока не будет явно вызван метод f.close().

Файлы обязательно надо закрывать

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

Помимо стандартного интерпретатора CPython еще есть множество других, например PyPy. Его автор в одном из комментариев на Stackoverflow сказал, что всегда есть шанс, что после завершения работы программы файл, который не был закрыт принудительно до этого не будет закрыт правильно. И действительно, если убить процесс через менеджера процессов или командой kill, то события, которые были запланированы чтобы быть исполненными перед выходом из программы могут не случиться.

Просто сделайте правилом всегда вызывать метод .close() когда работа с файлом окончена.

Чтобы не вдаваться в сложные подробности хочу обратить внимание, что на самом деле в Python есть множество типов объектов ввода вывода. Но все они последовательно создают объекты с теми же свойствами и теми же методами, или говоря языком программиста предоставляют один и тот же интерфейс взаимодействия. В программировании явление когда разные объекты ведут себя схожим образом в шутку называют Утиная Типизация. Давайте рассмотрим основные методы и свойства таких объектов:

Метод или свойство Описание
close() Очистка буфера и закрытие потока или файла. Если файл уже закрыт, то попытки записи будут вызывать ValueError, но сам метод можно вызывать множество раз
closed True если файл или поток закрыт
fileno() Возвращает номер связанного с объектом файлового дескриптора. Вернет OSError если объект не использует файловый дескриптор
flush() Вызывает запись буфера файла на диск. Ничего не делает если файл открыт для чтения или если запись не используется блоковая запись
isatty() True если поток является интерактивным, например если это интерфейс ввода пользователем (терминал или tty )
readable() True если поток позволяет чтение. Если эта функция возвращает False то попытка чтения с помощью read() вызовет OSError
readline(size=-1) Прочитать строку из файла. Если size указан, то будет прочитано не больше size байт. Если файл открыт в бинарном режиме, то для разделения строк ипользуетс b'\n'; для текстовых можно использовать параметр newline функции open() для указания маркера новой строки
readlines(hint=-1) Прочитать строки из файла и вернуть в ввиде списка. hint указыват сколько строк читать, в этом случае будет считано не более hint строк
seek(offset[, whence]) Переместить текущую позицию в файле на offset байт. Направление задается параметром whence, он может быть цифровым или использовать константы модуля io: 0/io.SEEK_SET — начало файла, 1/io.SEEK_CUR относительно текущей позиции и 2/io.SEEK_END относительно конца файла. Возвращает абсолютную позицию.
seekable() True если файл или поток позволяет свободное перемещение курсора. Если функция вернет False то операции seek(), tell() и truncate() вызовут OSError.
tell() Возвращает текущее положение курсора
truncate(size=None) Изменяет размер файла до указанного размера, если size не указан, то обрезает файл в текущей позиции курсора. Если после операции размер файла увеличился, то в зависимости от платформы новое место заполняется нулевыми байтами.
writable() True если поток позволяет запись. Если эта функция возвращает False то операции write() и truncate() вызовут исключение OSError
writelines(lines) Записать строки lines в поток. Разделитель строк не будет автоматически добавлен в файл, поэтому каждая строка должна заканчиваться символом разделителя строк (обычно это \n)
__del__() или del f Деструктор объекта f, вызов оператора del f вызовет операцию удаления объекта из памяти. По умолчанию вызывается метод close()

Для объектов, которые связаны с чувствительными данными, например такими как файлы или соединения с базами данных, есть возможность сделать так называемые деструкторы. Это специальный магический метод с именем __del__ который вызывается в тот момент, когда объект должен очиститься из памяти. Это случается в тот момент, когда на объект больше не существует ссылок или когда явно вызывается оператор del с именем переменной, которая ссылается на объект. Но существует множество ситуация во время которых __del__ так и не будет вызван. Поэтому всегда лучше явно вызывать close или пользоваться конструкцией with, речь о которой пойдет в следующей главе.

image