如何在Python中使用“with open”打开多个文件?

我想一次更改几个文件,iff我可以写入所有文件。我想知道我是否可以以某种方式将多个打开调用与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

如果这是不可能的,那么这个问题的优雅解决方案会是什么样子?

427757 次浏览

从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"

请注意,更常见的是您希望按顺序处理文件,而不是同时打开所有文件,特别是如果您有可变数量的文件:

for fname in filenames:with open(fname) as f:# Process f

只需将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

对于一次打开多个文件或长文件路径,将内容分成多行可能会很有用。从@Sven Marnach在评论中建议的Python风格指南到另一个答案:

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())

嵌套语句会做同样的工作,在我看来,处理起来更直接。

假设您有inFile.txt,并希望同时将其写入两个outFile。

with open("inFile.txt", 'r') as fr:with open("outFile1.txt", 'w') as fw1:with open("outFile2.txt", 'w') as fw2:for line in fr.readlines():fw1.writelines(line)fw2.writelines(line)

编辑:

我不明白否决的原因。在发布答案之前,我测试了我的代码,它按预期工作:它会写入所有outFile,就像问题所问的那样。没有重复写入或未能写入。所以我真的很想知道为什么我的答案被认为是错误的、次优的或类似的东西。

使用python 2.6它将无法工作,我们必须使用以下方式打开多个文件:

with open('a', 'w') as a:with open('b', 'w') as b:

从Python 3.3开始,您可以使用contextlib模块中的类ExitStack安全地
打开任意数量的文件

它可以管理动态数量的上下文感知对象,这意味着它将被证明特别有用如果您不知道要处理多少文件

事实上,留档中提到的规范用例是管理动态数量的文件。

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.numX.num += 1
def __repr__(self):cls = type(self)return '{cls.__name__}{self.num}'.format(cls=cls, self=self)
def __enter__(self):print('enter {!r}'.format(self))return self.num
def __exit__(self, exc_type, exc_value, traceback):print('exit {!r}'.format(self))return True
xs = [X() for _ in range(3)]
with ExitStack() as stack:print(len(stack._exit_callbacks)) # number of callbacks called on exitnums = [stack.enter_context(x) for x in xs]print(len(stack._exit_callbacks))
print(len(stack._exit_callbacks))print(nums)

输出:

0enter X1enter X2enter X33exit X3exit X2exit X10[1, 2, 3]

延迟回答(8岁),但对于希望将多个文件合并为一个的人来说,以下功能可能会有所帮助:

def multi_open(_list):out=""for x in _list:try:with open(x) as f:out+=f.read()except:pass# print(f"Cannot open file {x}")return(out)
fl = ["C:/bdlog.txt", "C:/Jts/tws.vmoptions", "C:/not.exist"]print(multi_open(fl))

2018-10-23 19:18:11.361 PROFILE  [Stop Drivers] [1ms]2018-10-23 19:18:11.361 PROFILE  [Parental uninit] [0ms]...# This file contains VM parameters for Trader Workstation.# Each parameter should be defined in a separate line and the...

从Python 3.10开始,带括号的上下文管理器有一个新特性,它允许语法如下:

with (open("a", "w") as a,open("b", "w") as b):do_something()