繁体   English   中英

如何使用“ with open”语句打开多个文件(事先未知的文件数)?

[英]How can I open multiple files (number of files unknown beforehand) using “with open” statement?

我特别需要使用with open语句来打开文件,因为我需要一起打开几百个文件并使用K-way merge进行合并。 我了解,理想情况下我应该保持K低,但我没有预见到这个问题。

由于我有一个截止日期,因此现在不能从头开始。 因此,在这一点上,我需要非常快速的I / O,它不能将文件的整个/巨大部分存储在内存中(因为有数百个文件,每个文件约10MB)。 我只需要一次阅读一行即可进行K向合并。 减少内存使用是我目前的主要重点。

我了解到, with open是最有效的方法,但我不知道如何open所有文件一起在一个with open的语句。 对不起,我的初学者无知!

更新:此问题已解决。 事实证明,问题根本不在于我如何打开文件。 我发现过多的内存使用是由于低效率的垃圾回收所致。 我根本不使用with open 我使用了常规的f=open()f.close() 垃圾收集挽救了这一天。

通过使用内置的contextmanger函数装饰器来定义文档说明中的“ with语句上下文管理器的工厂函数”,从而编写自己的上下文管理器来处理此问题非常容易。 例如:

from contextlib import contextmanager

@contextmanager
def multi_file_manager(files, mode='rt'):
    """ Open multiple files and make sure they all get closed. """
    files = [open(file, mode) for file in files]
    yield files
    for file in files:
        file.close()

filenames = 'file1', 'file2', 'file3'

with multi_file_manager(filenames) as files:
    a = files[0].readline()
    b = files[2].readline()
        ...
with open(...) as f: 
    # do stuff 

大致翻译成

f = open(...)
# do stuff
f.close()

在您的情况下,我不会将with open语法with open使用。 如果您有文件名列表,请执行以下操作

filenames = os.listdir(file_directory)
open_files = map(open, filenames)
# do stuff
for f in open_files:
    f.close()

如果您确实想使用with open语法,则可以创建自己的上下文管理器来接受文件名列表

class MultipleFileManager(object):
    def __init__(self, files):
        self.files = files

    def __enter__(self):
        self.open_files = map(open, self.files)
        return self.open_files

    def __exit__(self):
        for f in self.open_files:
            f.close()

然后像这样使用它:

filenames = os.listdir(file_directory)
with MulitpleFileManager(filenames) as files:
    for f in files:
        # do stuff

在这种情况下,使用上下文管理器的唯一好处是您不会忘记关闭文件。 但是手动关闭文件没有任何问题。 记住,当您的程序退出时,操作系统将回收其资源。

虽然不是2.7的解决方案,我应该注意到有一个良好的,为3.3+正确的解决方案, contextlib.ExitStack ,它可以用来正确做到这一点(令人惊讶的困难,当你滚你自己得到的权利),并很好地:

from contextlib import ExitStack

with open('source_dataset.txt') as src_file, ExitStack() as stack:
    files = [stack.enter_context(open(fname, 'w')) for fname in fname_list]
    ... do stuff with src_file and the values in files ...
... src_file and all elements in stack cleaned up on block exit ...

重要的是,如果任何一个open失败,则将确定性地清除在该点之前成功的所有open 在这种情况下,大多数幼稚的解决方案最终都无法清理,只能依靠垃圾回收器,并且在诸如锁获取而没有对象可以收集的情况下,也无法释放锁。

由于此问题被标记为“原始”,表示未指定Python版本的重复项 ,因此在此处发布。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM