7

假设我有一个大文件,其中包含一些我希望忽略的行,以及一个file_function接受文件对象的函数 ( )。我可以在不先读取整个文件的情况下返回一个其行满足某些条件的新文件对象吗,这种懒惰是重要的部分。

注意:我可以只保存一个忽略这些行的临时文件,但这并不理想。

例如,假设我有一个 csv 文件(有一个坏行):

1,2
ooops
3,4

第一次尝试是创建新的文件对象(使用与文件相同的方法)并覆盖readline

class FileWithoutCondition(file):
    def __init__(self, f, condition):
        self.f = f
        self.condition = condition
    def readline(self):
        while True:
            x = self.f.readline()
            if self.condition(x):
                return x

如果file_name仅使用readline...,则此方法有效,但如果需要其他功能则无效。

with ('file_name', 'r') as f:
    f1 = FileWithoutOoops(f, lambda x: x != 'ooops\n')
    result = file_function(f1)

使用 StringIO 的解决方案可能有效,但我似乎无法做到。

理想情况下,我们应该假设这file_function是一个黑盒函数,特别是我不能只调整它以接受生成器(但也许我可以将生成器调整为类似文件?)。
是否有一种标准方法可以对通用文件进行这种惰性(略读)阅读?

注意:这个问题的激励例子是这个 pandas question,仅仅有一个readline不足以开始pd.read_csv工作......

4

1 回答 1

1

使用现有 Python 工具的 map-reduce 方法。在此示例中,我使用正则表达式来匹配以 string 开头的行GET /index,但您可以使用适合您账单的任何条件:

import re
from collections import defaultdict

pattern = re.compile(r'GET /index\(.*\).html')

# define FILE appropriately.
# map
# the condition here serves to filter lines that can not match.
matches = (pattern.search(line) for line in file(FILE, "rb") if 'GET' in line)
mapp    = (match.group(1) for match in matches if match)

# now reduce, lazy:
count = defaultdict(int)
for request in mapp:
    count[request] += 1

这会在几秒钟内扫描我笔记本电脑上的 >6GB 文件。您可以进一步将文件分成块并将它们提供给线程或进程。mmap除非您有内存来映射整个文件(它不支持窗口化),否则不建议使用。

于 2013-02-26T13:58:38.587 回答