如何在Python中同时读取和处理多个文件

3 投票
1 回答
11483 浏览
提问于 2025-04-18 09:03

我有很多文件,想要同时读取它们,从每一行中提取一个数字,然后计算平均值。对于少量文件,我是用itertools模块里的izip来实现的。以下是我的代码。

from itertools import izip
import math

g=open("MSDpara_ave_nvt.dat",'w')

with open("sample1/err_msdCECfortran_nvt.dat",'r') as f1, \
     open("sample2/err_msdCECfortran_nvt.dat",'r') as f2, \
     open("sample3/err_msdCECfortran_nvt.dat",'r') as f3, \
     open("err_msdCECfortran_nvt.dat",'r') as f4:

     for x,y,z,bg in izip(f1,f2,f3,f4):
         args1=x.split()
         i1 = float(args1[0])
         msd1 = float(args1[1])


         args2=y.split()
         i2 = float(args2[0])
         msd2 = float(args2[1])


         args3=z.split()
         i3 = float(args3[0])
         msd3 = float(args3[1])

         args4=bg.split()
         i4 = float(args4[0])
         msd4 = float(args4[1])


         msdave = (msd1 + msd2 + msd3 + msd4)/4.0

         print>>g, "%e  %e" %(i1, msdave)

 f1.close()
 f2.close()
 f3.close()
 f4.close()
 g.close()

这段代码运行得还不错。不过,如果我想同时处理100个文件,这样写代码就会变得很冗长。有没有更简单的方法呢?我听说fileinput模块也可以处理多个文件,但我不确定它是否能同时处理。

谢谢。

1 个回答

11

使用 with open 这种写法是很不错的,但在这个情况下,它可能会让你觉得麻烦。你可以先打开一个文件列表,然后在 izip 中使用这个列表:

filenames = ["sample1/err_msdCECfortran_nvt.dat",...]
files = [open(i, "r") for i in filenames]
for rows in izip(*files):
    # rows is now a tuple containing one row from each file

在 Python 3.3 及以上版本中,你还可以在 with 代码块中使用 ExitStack

filenames = ["sample1/err_msdCECfortran_nvt.dat",...]
with ExitStack() as stack:
    files = [stack.enter_context(open(i, "r")) for i in filenames]
    for rows in zip(*files):
        # rows is now a tuple containing one row from each file

如果你使用的是 Python 3.3 以下的版本,想要享受 with 的所有好处(比如无论你怎么退出这个代码块都能及时关闭文件),你需要自己创建一个上下文管理器:

class FileListReader(object):

    def init(self, filenames):
        self.files = [open(i, "r") for i in filenames]

    def __enter__(self):
        for i in files:
            i.__enter__()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        for i in files:
            i.__exit__(exc_type, exc_value, traceback)

然后你可以这样做:

filenames = ["sample1/err_msdCECfortran_nvt.dat",...]
with FileListReader(filenames) as f:
    for rows in izip(*f.files):
        #...

不过在这种情况下,最后的做法可能会显得有些复杂。

撰写回答