Python 在读取之前懒散地过滤文件

Python 在读取之前懒散地过滤文件,python,file,Python,File,假设我有一个大文件,其中有一些我希望忽略的行,还有一个函数(file\u function),它接受一个file对象。我是否可以返回一个新的文件对象,该对象的行满足某些条件,而不首先读取整个文件,这是重要的部分 注意:我可以保存一个临时文件,忽略这些行,但这并不理想 例如,假设我有一个csv文件(行不正确): 第一次尝试是创建新的文件对象(使用与文件相同的方法)并覆盖readline: class FileWithoutCondition(file): def __init__(self

假设我有一个大文件,其中有一些我希望忽略的行,还有一个函数(
file\u function
),它接受一个file对象。我是否可以返回一个新的文件对象,该对象的行满足某些条件,而不首先读取整个文件,这是重要的部分

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

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

第一次尝试是创建新的文件对象(使用与文件相同的方法)并覆盖
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
如果
文件名
仅使用
读线
。。。但如果它需要其他一些功能,就不需要了

使用StringIO的解决方案可能有效,但我似乎无法实现

理想情况下,我们应该假设
file\u函数
是一个黑盒函数,具体地说,我不能仅仅调整它以接受生成器(但也许我可以将生成器调整为类似于文件?。
有没有一种标准方法可以对通用文件进行这种惰性(略读)读取?


注意:这个问题的激励示例是,仅仅拥有
readline
不足以获得
pd.read\u csv
工作…

使用现有Python工具的map reduce方法。在本例中,我使用正则表达式匹配以字符串
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
我不建议您使用,除非您有内存映射整个文件(它不支持窗口)。

我认为您需要为我们明确说明“文件”对象的具体要求。如果它需要的不仅仅是生成行的能力,我们需要知道还有什么。@JohnZwinck我想你可能是对的,我希望能有一些通用的方法来做到这一点(可以处理任何“文件”。也许这很幼稚……也许。:)如果你还没有的话,请检查。@JohnZwinck谢谢你,我没有看到它!这不是一个生成器而不是像文件一样吗?与下面的答案(已删除)类似?这是一个问题吗?您可以将
mapp=…
生成器像类“
readline
一样封装在您的文件中,并从中获得收益,但我不会这样做,因为文件没有抽象类,所以您必须实现所有方法。也许一个文件没有抽象类是个问题,我希望我可以假装它是一个文件。has
file\u function=pd.read\u csv
(需要的不仅仅是readline):(
with ('file_name', 'r') as f:
    f1 = FileWithoutOoops(f, lambda x: x != 'ooops\n')
    result = file_function(f1)
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