假设我有一个大文件,其中包含一些我希望忽略的行,以及一个接受文件对象的函数 (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
是一个黑盒函数,具体来说,我不能仅仅调整它来接受一个生成器(但也许我可以将一个生成器调整为类文件?)。< br/>
是否有一种标准方法可以对通用文件进行这种惰性(略读)读取?
注意:这个问题的激励示例是 this pandas question ,只有 readline
不足以让 pd.read_csv
工作...
最佳答案
将 map-reduce 方法与现有的 Python 工具结合使用。在此示例中,我使用正则表达式来匹配以字符串 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 的文件。您可以进一步将文件分成 block 并将它们提供给线程或进程。使用 mmap
我不推荐,除非你有足够的内存来映射整个文件(它不支持窗口化)。
关于python - 在阅读之前懒惰地过滤文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15090685/