我想逐行或逐块同时读取一些文件(其数量尚未确定),要进行处理并移至所有文件中的下一行(或块) 。我猜我的要求与this question中的要求或多或少相似。但是,在我的情况下,文件可以具有不同的行数,并且在尝试实现类似ExitStack之类的内容时,请注意,一旦关闭其中一个文件,所有文件都将被关闭(可能是最小的文件)。行数),而我想继续处理其他文件(最终将空字符串分配给已关闭文件的“行”)。这有可能实现吗?又如何?
#cat f1.txt
RNvn 40
AvOp 13
yEVA 94
oNGn 10
VZQU 88
#cat f2.txt
gSNn 4
zxHP 84
ebRw 70
NaxL 2
lXUb 49
PQzn 79
aIyN 88
#cat f3.txt
XXce 5
RMIq 4
FFEi 47
wuLZ 60
使用ExitStack
的简单实现,结果仅包括4行,因为文件f3.txt
仅具有4行:
flist = ['f1.txt', 'f2.txt', 'f3.txt']
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in flist]
for lines in zip(*files):
print(lines)
# prints
('RNvn 40\n', 'gSNn 4\n', 'XXce 5\n')
('AvOp 13\n', 'zxHP 84\n', 'RMIq 4\n')
('yEVA 94\n', 'ebRw 70\n', 'FFEi 47\n')
('oNGn 10\n', 'NaxL 2\n', 'wuLZ 60\n')
答案 0 :(得分:3)
您可以使用两全其美的方式。
代码离开上下文with ExitStack() as stack:
,因为最短文件上的zip()
已用尽。与ExitStack()
无关。在完成所有文件之前,不会用尽zip_longest()
。然后ExitStack()
将关闭文件。
from contextlib import ExitStack
from itertools import zip_longest
flist = ['f1.txt', 'f2.txt', 'f3.txt']
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in flist]
for lines in zip_longest(*files):
print(lines)
答案 1 :(得分:0)
回答我自己的问题,但请随时添加任何注释/改进/替代方案。
解决此问题的一种方法是打开所有文件,而无需使用with
语句继续读取直到读取所有文件,然后使用itertools
中的zip_longest来收集所有文件线同时。最后关闭所有文件。以下代码行中的内容应该可以工作:
from itertools import zip_longest
flist = ['f1.txt', 'f2.txt', 'f3.txt']
files = [open(i, 'rt') for i in flist]
for lines in zip_longest(*files):
print(lines)
for f in files:
f.close()
# this prints all lines as expected:
('RNvn 40\n', 'gSNn 4\n', 'XXce 5\n')
('AvOp 13\n', 'zxHP 84\n', 'RMIq 4\n')
('yEVA 94\n', 'ebRw 70\n', 'FFEi 47\n')
('oNGn 10\n', 'NaxL 2\n', 'wuLZ 60\n')
('VZQU 88\n', 'lXUb 49\n', None)
(None, 'PQzn 79\n', None)
(None, 'aIyN 88\n', None)