Файлы. Работа с файлами. | Python 3 для начинающих и чайников
В данной статье мы рассмотрим встроенные средства python для работы с файлами: открытие / закрытие, чтение и запись.
Итак, начнем. Прежде, чем работать с файлом, его надо открыть. С этим замечательно справится встроенная функция open:
f = open('text.txt', 'r')
У функции open много параметров, они указаны в статье «Встроенные функции», нам пока важны 3 аргумента: первый, это имя файла. Путь к файлу может быть относительным или абсолютным. Второй аргумент, это режим, в котором мы будем открывать файл.
Режим | Обозначение |
‘r’ | открытие на чтение (является значением по умолчанию). |
‘w’ | открытие на запись, содержимое файла удаляется, если файла не существует, создается новый. |
‘x’ | открытие на запись, если файла не существует, иначе исключение. |
‘a’ | открытие на дозапись, информация добавляется в конец файла. |
‘b’ | открытие в двоичном режиме. |
‘t’ | открытие в текстовом режиме (является значением по умолчанию). |
‘+’ | открытие на чтение и запись |
Режимы могут быть объединены, то есть, к примеру, ‘rb’ — чтение в двоичном режиме. По умолчанию режим равен ‘rt’.
И последний аргумент, encoding, нужен только в текстовом режиме чтения файла. Этот аргумент задает кодировку.
Чтение из файла
Открыли мы файл, а теперь мы хотим прочитать из него информацию. Для этого есть несколько способов, но большого интереса заслуживают лишь два из них.
Первый — метод read, читающий весь файл целиком, если был вызван без аргументов, и n символов, если был вызван с аргументом (целым числом n).
>>> f = open('text.txt') >>> f.read(1) 'H' >>> f.read() 'ello world!\nThe end.\n\n'
Ещё один способ сделать это — прочитать файл построчно, воспользовавшись циклом for:
>>> f = open('text. txt') >>> for line in f: ... line ... 'Hello world!\n' '\n' 'The end.\n' '\n'
Запись в файл
Теперь рассмотрим запись в файл. Попробуем записать в файл вот такой вот список:
>>> l = [str(i)+str(i-1) for i in range(20)] >>> l ['0-1', '10', '21', '32', '43', '54', '65', '76', '87', '98', '109', '1110', '1211', '1312', '1413', '1514', '1615', '1716', '1817', '1918']
Откроем файл на запись:
>>> f = open('text.txt', 'w')
Запись в файл осуществляется с помощью метода write:
>>> for index in l: ... f.write(index + '\n') ... 4 3 3 3 3
Для тех, кто не понял, что это за цифры, поясню: метод write возвращает число записанных символов.
После окончания работы с файлом его обязательно нужно закрыть с помощью метода close:
>>> f.close()
Теперь попробуем воссоздать этот список из получившегося файла. Откроем файл на чтение (надеюсь, вы поняли, как это сделать?), и прочитаем строки.
>>> f = open('text.txt', 'r') >>> l = [line.strip() for line in f] >>> l ['0-1', '10', '21', '32', '43', '54', '65', '76', '87', '98', '109', '1110', '1211', '1312', '1413', '1514', '1615', '1716', '1817', '1918'] >>> f.close()
Мы получили тот же список, что и был. В более сложных случаях (словарях, вложенных кортежей и т. д.) алгоритм записи придумать сложнее. Но это и не нужно. В python уже давно придумали средства, такие как pickle или json, позволяющие сохранять в файле сложные структуры.
Для вставки кода на Python в комментарий заключайте его в теги <pre><code>Ваш код</code></pre>
Изучаем Python: работа с файлами
В этой статье мы рассмотрим операции с файлами в Python. Открытие файла Python. Чтение из файла Python. Запись в файл Python, закрытие файла. А также методы, предназначенные для работы с файлами.
- Работа с файлами питон — что такое файл Python?
- Открытие файла Python
- Как закрыть файл в Python?
- Запись в файл Python
- Чтение из файла Python
- Python работа с файлами — основные методы
Файл – это именованная область диска, предназначенная для длительного хранения данных в постоянной памяти (например, на жёстком диске).
Чтобы прочитать или записать данные в файл, сначала нужно его открыть. После окончания работы файл необходимо закрыть, чтобы освободить связанные с ним ресурсы.
Поэтому в Python операции с файлами выполняются в следующем порядке:
- Открытие файла Python.
- Чтение из файла Python или запись в файл Python (выполнение операции).
- Закрытие файла Python.
Не знаете как открыть файл в питоне? В Python есть встроенная функция open(), предназначенная для открытия файла. Она возвращает объект, который используется для чтения или изменения файла.
>>> f = open("test.txt") # открыть файл в текущей папке >>> f = open("C:/Python33/README.txt") # указание полного пути
При этом можно указать необходимый режим открытия файла: ‘r’- для чтения,’w’ — для записи,’a’ — для изменения. Мы также можем указать, хотим ли открыть файл в текстовом или в бинарном формате.
По умолчанию файл открывается для чтения в текстовом режиме. При чтении файла в этом режиме мы получаем строки.
В бинарном формате мы получим байты. Этот режим используется для чтения не текстовых файлов, таких как изображения или exe-файлы.
Открытие файла Python- возможные режимы | |
Режим | Описание |
‘r’ | Открытие файла для чтения. Режим используется по умолчанию. |
‘w’ | Открытие файла для записи. Режим создаёт новый файл, если он не существует, или стирает содержимое существующего. |
‘x’ | Открытие файла для записи. Если файл существует, операция заканчивается неудачей (исключением). |
‘a’ | Открытие файла для добавления данных в конец файла без очистки его содержимого. Этот режим создаёт новый файл, если он не существует. |
‘t’ | Открытие файла в текстовом формате. Этот режим используется по умолчанию. |
‘b’ | Открытие файла в бинарном формате. |
‘+’ | Открытие файла для обновления (чтения и записи). |
f = open("test.txt") # эквивалент 'r' или 'rt' f = open("test.txt",'w') # запись в текстовом режиме f = open("img.bmp",'r+b') # чтение и запись в бинарном формате
В отличие от других языков программирования, в Python символ ‘a’ не подразумевает число 97, если оно не закодировано в ASCII (или другой эквивалентной кодировке).
Кодировка по умолчанию зависит от платформы. В Windows – это ‘cp1252’, а в Linux ‘utf-8’.
Поэтому мы не должны полагаться на кодировку по умолчанию. При работе с файлами в текстовом формате рекомендуется указывать тип кодировки.
f = open("test.txt",mode = 'r',encoding = 'utf-8')
Закрытие освободит ресурсы, которые были связаны с файлом. Это делается с помощью метода close(), встроенного в язык программирования Python.
В Python есть сборщик мусора, предназначенный для очистки ненужных объектов, Но нельзя полагаться на него при закрытии файлов.
f = open("test.txt",encoding = 'utf-8') # выполнение операций с файлом f.close()
Этот метод не полностью безопасен. Если при операции возникает исключение, выполнение будет прервано без закрытия файла.
Более безопасный способ – использование блока try…finally.
try: f = open("test.txt",encoding = 'utf-8') # выполнение операций с файлом finally: f.close()
Это гарантирует правильное закрытие файла даже после возникновения исключения, прерывающего выполнения программы.
Также для закрытия файла можно использовать конструкцию with. Оно гарантирует, что файл будет закрыт при выходе из блока with. При этом не нужно явно вызывать метод close(). Это будет сделано автоматически.
with open("test.txt",encoding = 'utf-8') as f: # выполнение операций с файлом
Чтобы записать данные в файл в Python, нужно открыть его в режиме ‘w’, ‘a’ или ‘x’. Но будьте осторожны с режимом ‘w’. Он перезаписывает файл, если то уже существует. Все данные в этом случае стираются.
Запись строки или последовательности байтов (для бинарных файлов) осуществляется методом write(). Он возвращает количество символов, записанных в файл.
with open("test.txt",'w',encoding = 'utf-8') as f: f.write("my first filen") f.write("This filenn") f.write("contains three linesn")
Эта программа создаст новый файл ‘test.txt’. Если он существует, данные файла будут перезаписаны. При этом нужно добавлять символы новой строки самостоятельно, чтобы разделять строки.
Чтобы осуществить чтение из файла Python, нужно открыть его в режиме чтения. Для этого можно использовать метод read(size), чтобы прочитать из файла данные в количестве, указанном в параметре size. Если параметр size не указан, метод читает и возвращает данные до конца файла.
>>> f = open("test.txt",'r',encoding = 'utf-8') >>> f.read(4) # чтение первых 4 символов 'This' >>> f.read(4) # чтение следующих 4 символов ' is ' >>> f.read() # чтение остальных данных до конца файла 'my first filenThis filencontains three linesn' >>> f.read() # дальнейшие попытки чтения возвращают пустую строку ''
Метод read() возвращает новые строки как ‘n’. Когда будет достигнут конец файла, при дальнейших попытках чтения мы получим пустые строки.
Чтобы изменить позицию курсора в текущем файле, используется метод seek(). Метод tell() возвращает текущую позицию курсора (в виде количества байтов).
>>> f.tell() # получаем текущую позицию курсора в файле 56 >>> f. seek(0) # возвращаем курсор в начальную позицию 0 >>> print(f.read()) # читаем весь файл This is my first file This file contains three lines
Мы можем прочитать файл построчно в цикле for.
>>> for line in f: ... print(line, end = '') ... This is my first file This file contains three lines
Извлекаемые из файла строки включают в себя символ новой строки ‘n’. Чтобы избежать вывода, используем пустой параметр end метода print(),.
Также можно использовать метод readline(), чтобы извлекать отдельные строки. Он читает файл до символа новой строки.
>>> f.readline() 'This is my first filen' >>> f.readline() 'This filen' >>> f.readline() 'contains three linesn' >>> f.readline() ''
Метод readlines() возвращает список оставшихся строк. Все эти методы чтения возвращают пустую строку, когда достигается конец файла.
>>> f.readlines() ['This is my first filen', 'This filen', 'contains three linesn']
Ниже приводится полный список методов для работы с файлами в текстовом режиме.
Python работа с файлами — методы | |
Метод | Описание |
close() | Закрытие файла. Не делает ничего, если файл закрыт. |
detach() | Отделяет бинарный буфер от TextIOBase и возвращает его. |
fileno() | Возвращает целочисленный дескриптор файла. |
flush() | Вызывает сброс данных (запись на диск) из буфера записи файлового потока. |
isatty() | Возвращает значение True, если файловый поток интерактивный. |
read(n) | Читает максимум n символов из файла. Читает до конца файла, если значение отрицательное или None. |
readable() | Возвращает значение True, если из файлового потока можно осуществить чтение. |
readline(n=-1) | Читает и возвращает одну строку из файла. Читает максимум n байт, если указано соответствующее значение. |
readlines(n=-1) | Читает и возвращает список строк из файла. Читает максимум n байт/символов, если указано соответствующее значение. |
seek(offset,from=SEEK_SET) | Изменяет позицию курсора. |
seekable() | Возвращает значение True, если файловый поток поддерживает случайный доступ. |
tell() | Возвращает текущую позицию курсора в файле. |
truncate(size=None) | Изменяет размер файлового потока до size байт. Если значение size не указано, размер изменяется до текущего положения курсора. |
writable() | Возвращает значение True, если в файловый поток может производиться запись. |
write(s) | Записывает строки s в файл и возвращает количество записанных символов. |
writelines(lines) | Записывает список строк lines в файл. |
Сергей Бензенкоавтор-переводчик статьи «Python File IO Read and Write Files in Python»
Как открыть и закрыть файл в Python
Может возникнуть ситуация, когда нужно взаимодействовать с внешними файлами с помощью Python. Python предоставляет встроенные функции для создания, записи и чтения файлов. В этой статье мы обсудим, как открыть внешний файл и закрыть его с помощью Python.
Открытие файла в PythonСуществует два типа файлов, которые можно обрабатывать в Python: обычные текстовые файлы и двоичные файлы (написанные на двоичном языке, 0 и 1). Открытие файла относится к подготовке файла либо к чтению, либо к записи. Это можно сделать с помощью функция open() . Эта функция возвращает файловый объект и принимает два аргумента, один из которых принимает имя файла, а другой принимает режим (режим доступа).
Примечание: Файл должен находиться в том же каталоге, что и скрипт Python, в противном случае необходимо записать полный адрес файла.
Синтаксис: File_object = open(«File_Name», «Access_Mode»)
Параметры:
- File_Name: Это имя файла, который необходимо открыть.
- Access_Mode: Режимы доступа определяют тип операций, возможных в открытом файле. В таблице ниже приведены список всего режима доступа, доступного в Python
Операция | Синтаксис | Описание |
---|---|---|
только для чтения | R | . |
Чтение и запись | r+ | Открыть файл для чтения и записи. |
Только запись | w | Открыть файл для записи. |
Запись и чтение | w+ | Открыть файл для чтения и записи. В отличие от «r+», это не вызывает ошибку ввода-вывода, если файл не существует. |
Добавить только | a | Открыть файл для записи и создать новый файл, если он не существует. Все дополнения делаются в конце файла, и никакие существующие данные не могут быть изменены. |
Добавить и прочитать | a+ | Открыть файл для чтения и записи и создать новый файл, если он не существует. Все дополнения делаются в конце файла, и никакие существующие данные не могут быть изменены. |
В этом примере мы будем открывать файл только для чтения. Исходный файл выглядит следующим образом:
Код:
Python3
|
Здесь мы открыли файл и распечатали его содержимое.
Вывод:
Привет, Компьютерщик! Это образец текстового файла для примера.Пример 2: Открытие и запись в файл с помощью Python
В этом примере мы будем добавлять новое содержимое к существующему файлу. So the initial file looks like the below:
Code:
Python3
|
Теперь, если вы откроете файл, вы увидите приведенный ниже результат,
Вывод:
Пример 3: Открыть и перевернуть файл Pythonв этом примере. , мы перезапишем содержимое файла примера следующим кодом:
Код:
Python3
|
Приведенный выше код приводит к следующему результату:
Вывод:
Пример 4. Создание файла, если он не существует в Python
Метод path.touch() модуля pathlib создает файл в путь, указанный в пути path.touch().
Python3
|
Output:
Закрытие файла в Python
Как вы заметили, мы не закрыли ни один из файлов, над которыми мы работали в приведенных выше примерах. Хотя Python автоматически закрывает файл, если ссылочный объект файла выделяется для другого файла, стандартная практика — закрытие открытого файла, поскольку закрытый файл снижает риск необоснованного изменения или чтения.
Python имеет метод close() для закрытия файла. Метод close() можно вызывать более одного раза, и если какая-либо операция выполняется с закрытым файлом, возникает ошибка ValueError. В приведенном ниже коде показано простое использование метода close() для закрытия открытого файла.
Python3
|
|
Вывод:
ValueError: Операция ввода/вывода в закрытом файле.
Почему важно закрывать файлы в Python? – Real Python
В какой-то момент вашего пути к написанию кода на Python вы узнаете, что для открытия файлов следует использовать контекстный менеджер . Менеджеры контекста Python упрощают закрытие ваших файлов после того, как вы закончите с ними:
с помощью open("hello.txt", mode="w") в качестве файла: file.write("Привет, мир!")
Оператор с оператором
инициирует диспетчер контекста. В этом примере диспетчер контекста открывает файл hello.txt
и управляет файловым ресурсом, пока активен контекст . В общем, весь код в блоке с отступом зависит от того, какой файловый объект открыт. Как только блок с отступом заканчивается или вызывает исключение, файл закрывается.
Если вы не используете диспетчер контекста или работаете на другом языке, вы можете явно закрыть файлы с помощью попытка
… наконец
подход:
попытка: файл = открыть ("hello.txt", режим = "w") file.write("Привет, мир!") окончательно: файл.закрыть()
Блок finally
, который закрывает файл, выполняется безоговорочно, независимо от того, успешен или нет блок try
. Хотя этот синтаксис эффективно закрывает файл, менеджер контекста Python предлагает менее подробный и более интуитивно понятный синтаксис. Кроме того, это немного более гибко, чем просто обертывание вашего кода попробовать
… наконец
.
Вероятно, вы уже используете контекстные менеджеры для управления файлами, но задумывались ли вы когда-нибудь, почему большинство учебных пособий и четыре из пяти стоматологов рекомендуют это делать? Короче говоря, почему важно закрывать файлы в Python?
В этом уроке вы погрузитесь в этот вопрос. Во-первых, вы узнаете, что дескрипторы файлов являются ограниченным ресурсом . Затем вы поэкспериментируете с последствиями незакрытия ваших файлов.
Вкратце: файлы — это ресурсы, ограниченные операционной системой
Python делегирует файловые операции операционной системе . Операционная система является посредником между процессами , такими как Python, и всеми системными ресурсами , такими как жесткий диск, оперативная память и процессорное время.
Когда вы открываете файл с помощью open()
, вы делаете системный вызов в операционную систему, чтобы найти этот файл на жестком диске и подготовить его для чтения или записи. Затем операционная система вернет целое число без знака, называемое 9.дескриптор файла 0005 в Windows и дескриптор файла в UNIX-подобных системах, включая Linux и macOS:
. Когда у вас есть число, связанное с файлом, вы готовы выполнять операции чтения или записи. Всякий раз, когда Python хочет прочитать, записать или закрыть файл, он сделает еще один системный вызов, предоставив номер дескриптора файла. Файловый объект Python имеет метод .fileno()
, который можно использовать для поиска дескриптора файла:
>>>
>>> с open("test_file.txt", mode="w") в качестве файла: ... файл.fileno() . .. 4
Метод .fileno()
для открытого файлового объекта вернет целое число, используемое операционной системой в качестве файлового дескриптора. Точно так же, как вы можете использовать поле идентификатора для получения записи из базы данных, Python предоставляет этот номер операционной системе каждый раз, когда она читает или записывает файл.
Операционные системы ограничивают количество открытых файлов, которые может иметь один процесс . Обычно это число исчисляется тысячами. Операционные системы устанавливают это ограничение, потому что, если процесс пытается открыть тысячи файловых дескрипторов, вероятно, что-то не так с процессом. Несмотря на то, что тысячи файлов могут показаться большим количеством, все же можно достичь предела.
Помимо риска превышения лимита, сохранение файлов открытыми делает вас уязвимыми к потере данных . В общем, Python и операционная система прилагают все усилия, чтобы защитить вас от потери данных. Но если ваша программа или компьютер выйдет из строя, обычные процедуры могут не выполняться, а открытые файлы могут быть повреждены.
Примечание : Некоторые библиотеки имеют специальные методы и функции, которые, кажется, открывают файлы без менеджера контекста. Например, в библиотеке pathlib есть .write_text()
, а в pandas — read_csv()
.
Однако они правильно управляют ресурсами внутри, поэтому в таких случаях вам не нужно использовать контекстный менеджер. Лучше всего обратиться к документации по библиотеке, которую вы используете, чтобы узнать, нужен вам контекстный менеджер или нет.
Короче говоря, разрешение менеджерам контекста управлять вашими файлами — это защитная техника, которую легко практиковать, и она делает ваш код лучше, так что вы тоже можете это сделать. Это как пристегиваться ремнем безопасности. Вероятно, вам это не понадобится, но затраты на то, чтобы обойтись без него, могут быть высокими.
В оставшейся части этого руководства вы более глубоко познакомитесь с ограничениями, последствиями и опасностями незакрытия файлов. В следующем разделе вы изучите ошибку Слишком много открытых файлов
.
Удалить рекламу
Что происходит, когда вы открываете слишком много файлов?
В этом разделе вы узнаете, что происходит, когда вы достигаете предела файлов. Вы сделаете это, попробовав фрагмент кода, который создаст множество открытых файлов и спровоцирует Ошибка ОС
.
Примечание : как предполагает OS
в OSError
, ограничение применяется операционной системой, а не Python. Однако теоретически операционная система может работать с гораздо большим количеством файловых дескрипторов. Позже вы узнаете больше о том, почему операционная система ограничивает дескрипторы файлов.
Вы можете проверить лимит файлов на процесс в вашей операционной системе, попытавшись одновременно открыть тысячи файлов. Вы сохраните файловые объекты в списке, чтобы они не очищались автоматически. Но сначала вам нужно сделать некоторую уборку, чтобы убедиться, что вы не создаете много файлов там, где они вам не нужны:
$ mkdir file_experiment $ cd file_experiment
Достаточно создать папку, в которую можно сбросить файлы, а затем перейти в эту папку. Затем вы можете открыть Python REPL и попытаться создать тысячи файлов:
>>>
>>> files = [open(f"file-{n}.txt", mode="w") для n в диапазоне (10_000)] Traceback (последний последний вызов): ... OSError: [Errno 24] Слишком много открытых файлов: «file-1021.txt»
Этот фрагмент пытается открыть десять тысяч файлов и сохранить их в списке. Операционная система начинает создавать файлы, но отбрасывает их, как только достигает своего предела. Если вы перечислите файлы во вновь созданном каталоге, вы заметите, что даже несмотря на то, что понимание списка в конечном итоге дало сбой, операционная система создала многие из файлов — но не те десять тысяч, которые вы просили.
Ограничение, с которым вы столкнетесь, зависит от операционной системы и кажется больше по умолчанию в Windows. В зависимости от операционной системы существуют способы увеличить это ограничение файлов на процесс. Тем не менее, вы должны спросить себя, действительно ли вам это нужно. Есть только несколько законных вариантов использования для выбора этого решения.
Один допустимый сценарий для серверов. Серверы работают с сокетами, которые во многом похожи на файлы. Операционная система отслеживает сокеты в таблице файлов, используя дескрипторы файлов. Серверу может потребоваться открыть много сокетов для каждого клиента, к которому они подключаются. Кроме того, сервер может обмениваться данными с несколькими клиентами. Эта ситуация может привести к тому, что потребуются многие тысячи файловых дескрипторов.
Как ни странно, несмотря на то, что некоторые приложения могут требовать увеличения лимита операционной системы для открытых файлов, обычно именно эти приложения должны быть особенно внимательны при закрытии файлов!
Возможно, вы думаете, что вам не грозит непосредственная опасность достижения предела. Тем не менее, читайте дальше, потому что в следующем разделе вы более подробно рассмотрите некоторые последствия случайного превышения этого предела.
Каковы реальные последствия превышения лимита файлов?
Если вы открываете файлы и никогда не закрываете их в Python, вы можете не заметить никакой разницы, особенно если вы работаете над однофайловыми сценариями или небольшими проектами. Однако по мере того, как проекты, над которыми вы работаете, усложняются, вы будете все чаще сталкиваться с проблемными ситуациями.
Представьте, что вы работаете в большой команде над огромной кодовой базой. Затем в один прекрасный день вы достигнете предела для открытых файлов. Фишка в том, что сообщение об ошибке для лимита не скажет вам , где проблема. Это будет универсальный OSError
, которую вы видели ранее, которая сообщает вам только Слишком много открытых файлов
.
В вашей кодовой базе могут быть тысячи мест, где вы открываете файлы. Представьте себе поиск мест, где код неправильно обрабатывает файлы. Представьте, что код передает файловые объекты между функциями, и вы не можете сразу сказать, закрыт какой-либо данный файловый объект в конечном итоге или нет. Это не веселое время.
Если вам интересно, есть способы изучить дескрипторы открытых файлов вашей системы. Разверните следующий блок для изучения:
- Окна
- Linux + macOS
Установка процесса хакера:
PS> выборочная установка процесса хакера
Откройте приложение и нажмите кнопку Найти дескрипторы или библиотеки DLL . Установите флажок regex и введите .*
, чтобы увидеть все дескрипторы файлов с сопутствующей информацией.
Официальная версия Microsoft process hacker входит в состав утилит Sysinternals, а именно Process Monitor и Process Explorer.
Возможно, вам потребуется установить lsof
, утилиту Linux для l i s t o pen f файлов. С помощью этой утилиты можно получить информацию и подсчитать количество открытых файлов:
$ lsof | голова $ лсоф | туалет -л
Команда lsof
печатает новую строку для каждого открытого файла с основной информацией об этом файле. Введя его в команду head
, вы увидите начало вывода, включая имена столбцов.
Вывод lsof
может быть передан в команду wc
или подсчет слов. Переключатель -l
означает, что будут учитываться только новые строки. Вероятно, это число будет исчисляться сотнями тысяч.
Вы можете направить вывод lsof
в grep
, чтобы найти строки, содержащие строку типа python
. Вы также можете передать идентификатор процесса, который может быть полезен, если вы хотите найти файловые дескрипторы:
$ lsof | питон
Эта команда отфильтрует все строки, которые не содержат термин после grep
, в данном случае python
.
Если вас интересует теоретический предел для файлов в вашей системе, вы можете изучить его в системах на базе UNIX, изучив содержимое специального файла:
$ cat /proc/sys/fs/file-max
Число сильно зависит от платформы, но, скорее всего, оно велико. Система почти наверняка исчерпает другие ресурсы, прежде чем достигнет этого предела.
Вы можете задаться вопросом почему операционная система ограничивает файлы. Предположительно, он может обрабатывать гораздо больше файловых дескрипторов, чем показывает, верно? В следующем разделе вы узнаете, почему операционная система заботится об этом.
Почему операционная система ограничивает число дескрипторов файлов?
Фактические пределы количества файлов, которые операционная система может держать открытыми одновременно, огромны. Вы говорите о миллионах файлов. Но на самом деле достижение этого предела и присвоение ему фиксированного числа не является четким. Как правило, система исчерпает другие ресурсы раньше, чем закончатся дескрипторы файлов.
Ограничение является консервативным с точки зрения операционной системы, но достаточным с точки зрения большинства программ. С точки зрения операционной системы, любой процесс, который достигает предела, вероятно, приводит к утечке файловых дескрипторов вместе с другими ресурсами.
Утечка ресурсов может быть вызвана плохой практикой программирования или попыткой вредоносной программы атаковать систему. Вот почему операционная система накладывает ограничения — чтобы уберечь вас от других и от самого себя!
Плюс, для большинства приложений нет смысла открывать столько файлов. На одном жестком диске одновременно может выполняться не более одной операции чтения или записи, поэтому если вы работаете только с файлами, процесс не ускорится.
Итак, вы знаете, что открывать много файлов проблематично, но есть и другие недостатки, связанные с тем, что вы не закрываете файлы в Python, даже если вы открываете только несколько.
Удалить рекламу
Что произойдет, если вы не закроете файл и произойдет сбой Python?
В этом разделе вы поэкспериментируете с моделированием сбоя и увидите, как это влияет на открытые файлы. Вы можете использовать специальную функцию в модуле os
, которая завершится без выполнения какой-либо очистки, которую обычно делает Python, но сначала вы увидите, как обычно происходит очистка.
Выполнение операций записи для каждой команды может быть дорогостоящим. По этой причине по умолчанию Python использует буфер, который собирает операции записи. Когда буфер заполняется или когда файл явно закрывается, буфер сбрасывается, и операция записи завершается.
Python усердно работает, чтобы убрать за собой. В большинстве случаев он сам проактивно очищает и закрывает файлы:
# write_hello.py файл = открыть ("hello.txt", режим = "w") file.write("Привет, мир!")
При выполнении этого кода операционная система создает файл. Операционная система также записывает содержимое, даже если вы никогда не очищаете и не закрываете файл в коде. Об этой очистке и закрытии заботится подпрограмма очистки, которую Python выполнит в конце выполнения.
Однако иногда выходы не так контролируются, и сбой может привести к обходу этой очистки:
# сбой_hello. py импорт ОС файл = открыть ("crash.txt", режим = "w") file.write("Привет, мир!") os._exit(1)
После запуска фрагмента выше вы можете использовать cat
для проверки содержимого только что созданного файла:
$ кошка краш.txt $ # Нет вывода!
Вы увидите, что несмотря на то, что операционная система создала файл, в нем нет содержимого. Отсутствие выхода, потому что os._exit()
обходит обычную процедуру выхода Python, имитируя сбой. Тем не менее, даже этот тип симуляции относительно контролируем, поскольку предполагает, что произошел сбой Python, а не вашей операционной системы.
За кулисами, как только Python завершится, операционная система также выполнит собственную очистку, закрыв все файловые дескрипторы, открытые процессом. Сбои могут возникать на многих уровнях и мешать очистке операционной системы, оставляя дескрипторы файлов «висящими».
В Windows, например, висячие дескрипторы файлов могут быть проблематичными, поскольку любой процесс, который открывает файл, также блокирует его. Другой процесс не может открыть этот файл, пока он не будет закрыт. Пользователи Windows могут быть знакомы с мошенническими процессами, которые не позволяют вам открывать или удалять файлы.
Что может быть хуже блокировки файлов? Утечка файловых дескрипторов может представлять угрозу безопасности, поскольку разрешения, связанные с файлами, иногда смешиваются.
Примечание : Наиболее распространенная реализация Python, CPython, идет дальше в очистке дескрипторов оборванных файлов, чем вы думаете. Он использует подсчет ссылок для сборки мусора, поэтому файлы закрываются, когда на них больше не ссылаются. Тем не менее, другие реализации, такие как PyPy, используют другие стратегии, которые могут быть не такими агрессивными при очистке неиспользуемых файловых дескрипторов.
Тот факт, что некоторые реализации могут выполнять очистку не так эффективно, как CPython, является еще одним аргументом в пользу постоянного использования менеджера контекста!
Утечка файловых дескрипторов и потеря содержимого в буфере — это уже достаточно плохо, но сбой, прерывающий операцию с файлом, также может привести к повреждению файла. Это значительно увеличивает вероятность потери данных. Опять же, это маловероятные сценарии, но они могут быть дорогостоящими.
Вы никогда не сможете полностью оградить себя от сбоя, но вы можете уменьшить воздействие, используя контекстный менеджер. Синтаксис менеджера контекста, естественно, приведет вас к коду, который будет держать файл открытым только до тех пор, пока он необходим.
Заключение
Вы узнали почему важно закрывать файлы в Python . Поскольку файлы — это ограниченные ресурсы, которыми управляет операционная система, убедитесь, что файлы закрыты после использования, чтобы защитить от сложных для отладки проблем, таких как исчерпание файловых дескрипторов или повреждение данных. Лучшая защита — всегда открывать файлы с помощью контекстного менеджера.
Копаясь глубже, вы увидели, что происходит, когда вы открываете слишком много файлов, и вы спровоцировали сбой, который приводит к пропаже содержимого файла. Дополнительные сведения об открытии файлов см.