Как я могу открыть несколько файлов, используя «с открытым» в Python?
Я хочу изменить пару файлов одновременно, если я смогу записать их все. Мне интересно, могу ли я как-то объединить несколько открытых вызовов с with заявление:
try: with open('a', 'w') as a and open('b', 'w') as b: do_something() except IOError as e: print 'Operation failed: %s' % e.strerror
Если это невозможно, как будет выглядеть элегантное решение этой проблемы?
8 ответов
Начиная с Python 2.7 (или 3.1 соответственно) вы можете написать
with open('a', 'w') as a, open('b', 'w') as b: do_something()
В более ранних версиях Python вы можете иногда использовать contextlib.nested() вкладывать контекстные менеджеры. Это не будет работать, как ожидается, для открытия нескольких файлов — подробности смотрите в связанной документации.
В редком случае, когда вы хотите открыть переменное количество файлов одновременно, вы можете использовать contextlib.ExitStack начиная с Python версии 3.3:
with ExitStack() as stack: files = [stack.enter_context(open(fname)) for fname in filenames] # Do something with "files"
Однако в большинстве случаев у вас есть переменный набор файлов, но вы, вероятно, захотите открывать их один за другим.
Просто замени and с , и вы сделали:
try: with open('a', 'w') as a, open('b', 'w') as b: do_something() except IOError as e: print 'Operation failed: %s' % e.strerror
Для одновременного открытия большого количества файлов или для длинных путей к файлам может быть полезно разбить элементы на несколько строк. Из Руководства по стилю Python, предложенного @Sven Marnach в комментариях к другому ответу:
with open('/path/to/InFile.ext', 'r') as file_1, \ open('/path/to/OutFile.ext', 'w') as file_2: file_2.write(file_1.read())
В Python 3.10 появилась новая функция диспетчеров контекста в скобках , которая допускает такой синтаксис:
with ( open("a", "w") as a, open("b", "w") as b ): do_something()
Начиная с Python 3.3, вы можете использовать класс ExitStack от contextlib модуль безопасно
открыть произвольное количество файлов.
Он может управлять динамическим числом контекстно-зависимых объектов, что означает, что он окажется особенно полезным, если вы не знаете, сколько файлов вы собираетесь обрабатывать.
Фактически, канонический вариант использования, упомянутый в документации, управляет динамическим числом файлов.
with ExitStack() as stack: files = [stack.enter_context(open(fname)) for fname in filenames] # All opened files will automatically be closed at the end of # the with statement, even if attempts to open files later # in the list raise an exception
Если вы заинтересованы в деталях, вот общий пример, чтобы объяснить, как ExitStack работает:
from contextlib import ExitStack class X: num = 1 def __init__(self): self.num = X.num X.num += 1 def __repr__(self): cls = type(self) return ''.format(cls=cls, self=self) def __enter__(self): print('enter '.format(self)) return self.num def __exit__(self, exc_type, exc_value, traceback): print('exit '.format(self)) return True xs = [X() for _ in range(3)] with ExitStack() as stack: print(len(stack._exit_callbacks)) # number of callbacks called on exit nums = [stack.enter_context(x) for x in xs] print(len(stack._exit_callbacks)) print(len(stack._exit_callbacks)) print(nums)
0 enter X1 enter X2 enter X3 3 exit X3 exit X2 exit X1 0 [1, 2, 3]
Конструкция with#
В Python существует более удобный способ работы с файлами, чем те, которые использовались до сих пор — конструкция with :
In [1]: with open('r1.txt', 'r') as f: . for line in f: . print(line) . ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !
Кроме того, конструкция with гарантирует закрытие файла автоматически.
Обратите внимание на то, как считываются строки файла:
Когда с файлом нужно работать построчно, лучше использовать такой вариант.
В предыдущем выводе, между строками файла были лишние пустые строки, так как print добавляет ещё один перевод строки.
Чтобы избавиться от этого, можно использовать метод rstrip :
In [2]: with open('r1.txt', 'r') as f: . for line in f: . print(line.rstrip()) . ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 ! In [3]: f.closed Out[3]: True
И конечно же, с конструкцией with можно использовать не только такой построчный вариант считывания, все методы, которые рассматривались до этого, также работают:
In [4]: with open('r1.txt', 'r') as f: . print(f.read()) . ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !
Открытие двух файлов#
Иногда нужно работать одновременно с двумя файлами. Например, надо записать некоторые строки из одного файла, в другой.
В таком случае, в блоке with можно открывать два файла таким образом:
In [5]: with open('r1.txt') as src, open('result.txt', 'w') as dest: . : for line in src: . : if line.startswith('service'): . : dest.write(line) . : In [6]: cat result.txt service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers
Это равнозначно таким двум блокам with:
In [7]: with open('r1.txt') as src: . : with open('result.txt', 'w') as dest: . : for line in src: . : if line.startswith('service'): . : dest.write(line) . :
Работа с несколькими файлами в Python с использованием «with open»
Часто при работе с Python возникает необходимость одновременного открытия и работы с несколькими файлами. Попытка сделать это с помощью одного оператора «with open» может вызвать затруднения. Возьмем для примера следующий код:
try: with open('file1.txt', 'w') as file1 and open('file2.txt', 'w') as file2: pass except IOError as e: print('Operation failed: %s' % e.strerror)
Этот код вызовет ошибку, поскольку синтаксис Python не позволяет использовать оператор «and» в контексте менеджера контекста.
Однако, Python предлагает элегантное решение для работы с несколькими файлами. Можно использовать несколько операторов «with», объединив их в один блок:
try: with open('file1.txt', 'w') as file1, open('file2.txt', 'w') as file2: pass except IOError as e: print('Operation failed: %s' % e.strerror)
В этом случае Python открывает оба файла, и если не возникнет исключения IOError, то можно без проблем работать с обоими файлами внутри блока «with». При выходе из блока файлы автоматически закроются, что является одним из преимуществ использования менеджера контекста «with open».
Если же есть необходимость работать с большим количеством файлов, можно использовать циклы или списки для открытия файлов:
files = ['file1.txt', 'file2.txt', 'file3.txt'] try: handles = [open(file, 'w') for file in files] pass except IOError as e: print('Operation failed: %s' % e.strerror) finally: for handle in handles: handle.close()
Здесь используется генератор списка для открытия всех файлов в списке. После завершения работы с файлами, они все закрываются в блоке «finally».
Таким образом, Python предоставляет гибкие возможности для работы с несколькими файлами, позволяя удобно управлять их открытием и закрытием.
Метод open() в Python
Мы столкнулись с различными операциями, которые могут быть выполнены с файлом с помощью Python, например, чтение, запись или копирование. При выполнении любой из этих упомянутых операций обработки файлов было ясно, что открытие файла — это первый шаг.
Сегодня в этом руководстве мы сосредоточимся на части открытия файла с помощью метода Python open().
Метод open() открывает определенный файл в указанном режиме и возвращает файловый объект. Затем этот файловый объект можно использовать для выполнения различных операций с файлами. Синтаксис использования метода приведен ниже.
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
- файл относится к имени или дескриптору файла, а mode — это режим, в котором файл должен быть открыт. Это основные параметры, необходимые для открытия файла.
- Buffering — необязательное целое число, используемое для установки буферизации. По умолчанию установлено значение (-1),
- кодировка — это имя кодировки, используемой для декодирования или кодирования файла,
- errors — это необязательная строка, указывающая, как должны обрабатываться ошибки кодирования и декодирования. Обратите внимание, что это нельзя использовать в двоичном режиме.
- Новая строка определяет, как работает универсальный режим новой строки (применяется только к текстовому режиму). Это может быть None (по умолчанию), » , ‘\n’ , ‘\r’ и ‘\r\n’ .
- closefd указывает, является ли переданный параметр файла именем файла или дескриптором файла. Если упоминается файловый дескриптор, он должен иметь значение False. Или же True (по умолчанию). В противном случае возникнет ошибка,
- opener — это вызываемый настраиваемый параметр. Указанный файловый дескриптор для файлового объекта получается путем вызова средства opener с помощью (file, flags). opener должен возвращать дескриптор открытого файла (передача os.open качестве opener приводит к функциональности, аналогичной передаче None ).
Режимы открытия для open() в Python
Ниже приведены различные режимы открытия файлов с их значениями.
Режимы | Описание |
‘r’ | открыт для чтения (по умолчанию) |
‘w’ | открыть для записи, сначала обрезая файл |
‘x’ | открыть для монопольного создания, сбой, если файл уже существует |
‘a’ | открыть для записи, добавив в конец файла, если он существует |
‘b’ | двоичный режим |
‘t’ | текстовый режим (по умолчанию) |
‘+’ | открыт для обновления (чтение и запись) |
Пример
Мы собираемся открыть файл с именем file.txt с содержимым (как показано ниже) с помощью метода open() .
Внимательно посмотрите на приведенный ниже фрагмент кода.
# opening a file f = open('file.txt', 'r') # file object print("Type of f: ", type(f)) print("File contents:") for i in f: print(i) f.close() # closing file after successful operation
Type of f: File contents: Python Java Go C C++ Kotlin
Здесь мы открыли файл file.txt в режиме только для чтения ( ‘ r ‘ ). Метод open() возвращает объект файла в f . Затем мы прошли через этот объект, используя цикл for для доступа к содержимому файла.
После этого мы закрыли файл с помощью метода close(). Важно закрыть файл в конце после выполнения каких-либо операций с ним, чтобы избежать ошибок. Эти ошибки могут возникнуть при повторном открытии того же файла.
Открытие нескольких файлов
В Python мы можем открывать два или более файла одновременно, комбинируя оператор with, метод open() и оператор запятой ( ‘ , ‘ ). Давайте рассмотрим пример, чтобы лучше понять.
Здесь мы попытались открыть два независимых файла file1.txt и file2.txt и распечатать их соответствующее содержимое.
# opening multiple files try: with open('file1.txt', 'r+') as a, open('file2.txt', 'r+') as b: print("File 1:") for i in a: print(i) print("File 2:") for j in b: print(j) except IOError as e: print(f"An Error occured: ") # file closing is not required
File 1: John Alex Leo Mary Jim File 2: Sil Rantoff Pard Kim Parsons
Примечание: мы не закрывали файлы после использования этого времени. Это потому, что нам это не нужно, оператор with обеспечивает автоматическое закрытие открытых файлов путем вызова метода close().