Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 合并预先排序的文件而不将所有内容读入内存_Python - Fatal编程技术网

Python 合并预先排序的文件而不将所有内容读入内存

Python 合并预先排序的文件而不将所有内容读入内存,python,Python,我有一个日志文件列表,其中每个文件中的每一行都有一个时间戳,并且每一行在每个文件中按升序预先排序。不同的文件可以有重叠的时间范围,我的目标是将它们混合到一个大文件中,按时间戳排序。排序中可能存在关联,在这种情况下,我希望下一行来自输入列表中首先列出的任何文件 我已经看到了如何使用fileinput(请参阅)执行此操作的示例,但这似乎可以将所有文件读取到内存中。由于我的文件很大,这将是一个问题。因为我的文件是预先排序的,所以似乎应该有一种方法来使用它们,只需要考虑每个文件中最新的未探索的行。p>

我有一个日志文件列表,其中每个文件中的每一行都有一个时间戳,并且每一行在每个文件中按升序预先排序。不同的文件可以有重叠的时间范围,我的目标是将它们混合到一个大文件中,按时间戳排序。排序中可能存在关联,在这种情况下,我希望下一行来自输入列表中首先列出的任何文件


我已经看到了如何使用
fileinput
(请参阅)执行此操作的示例,但这似乎可以将所有文件读取到内存中。由于我的文件很大,这将是一个问题。因为我的文件是预先排序的,所以似乎应该有一种方法来使用它们,只需要考虑每个文件中最新的未探索的行。p> 您希望实现基于文件的。从两个文件中读取一行,输出旧的一行,然后从该文件中读取另一行。一旦其中一个文件用完,输出另一个文件的所有剩余行。

如果标准库中有
heapq.merge()
,为什么要自己滚动?不幸的是,它没有提供一个关键参数——你必须自己完成装饰-合并-取消装饰的舞蹈:

from itertools import imap
from operator import itemgetter
import heapq

def extract_timestamp(line):
    """Extract timestamp and convert to a form that gives the
    expected result in a comparison
    """
    return line.split()[1] # for example

with open("log1.txt") as f1, open("log2.txt") as f2:
    sources = [f1, f2]
    with open("merged.txt", "w") as dest:
        decorated = [
            ((extract_timestamp(line), line) for line in f)
            for f in sources]
        merged = heapq.merge(*decorated)
        undecorated = imap(itemgetter(-1), merged)
        dest.writelines(undecorated)
上面的每一步都是“懒惰”。正如我避免使用
file.readlines()
文件中的行是根据需要读取的。同样,装饰过程使用生成器表达式而不是列表comp
heapq.merge()
也是惰性的——它需要每个输入迭代器同时有一个项来进行必要的比较。最后,我将使用
itertools.imap()
,这是内置的map()的惰性变体,用于取消装饰


(在Python3中,map()变得懒惰,所以您可以使用它)

实际上,您只需要merge sort中的merge函数,而不是完整的算法。@Ignacio:谢谢。实际上,我熟悉mergesort中的merge方法,但我只是想找出一种最干净的方法来实现这一点,即python文件句柄和任意数量的文件同时被合并。这种解决方案不会导致所有的行同时驻留在内存中吗?@Peter:谢谢,这似乎很有效。就像马克一样,但我不明白这是如何避免把所有的东西都记在记忆里的。从我的内存使用情况来看,它似乎并没有将所有内容都加载到内存中,但在使用堆时它是如何做到这一点的,我不太明白。如果你有一个简明的解释,我会感兴趣的。@Abiel,我算出来了-
heapq.merge
返回一个iterable,而不是列表。甚至还特别提到了您的用例:“例如,合并来自多个日志文件的时间戳条目”。@Abiel,如果您在每行的开头都有一个好的时间戳格式,那么您甚至不需要进行装饰/取消装饰。我更喜欢。在传递给heapq之前,装饰程序会将所有行读入内存。你能从输入中添加两行吗?