如何避免Python文件输入缓冲

11

可能重复:
设置sys.stdin的较小缓冲区大小?

我有一个使用fileinput从标准输入或文件中读取数据的Python脚本(2.4 / 2.7)。 它易于使用,除了一种情况外都很好用:

tail -f log | filter.py
问题在于我的脚本会缓冲其输入,而(至少在这种情况下)我想立即看到其输出。这似乎源于fileinput使用readlines()在执行任何操作之前获取其bufsize大小的字节。我尝试过使用bufsize为1的选项,但似乎没有帮助(这让我有些惊讶)。
我发现我可以编写像这样的代码来避免缓冲:
while 1:
    line = sys.stdin.readline()
    if not line: break
    sys.stdout.write(line)

这种方法的问题在于我会失去fileinput功能(即它自动打开传递给程序的所有文件,如果没有,则使用标准输入,甚至可以自动解压缩输入文件)。

那么如何做到两全其美呢?理想情况下,我不需要显式地管理我的输入文件列表(包括解压缩),但在“流式”方式下使用时又不会延迟输入。


关闭stdin文件句柄并使用“buffering = 0”重新打开它(我还没有尝试过,所以不会将其发布为答案)。 - tMC
1
https://dev59.com/D3A65IYBdhLWcg3wuRF8 - David
你可能有些错误地描述了fileinput使用readlines()的情况。默认情况下,readlines()在遇到EOF之前不会返回,而'for line in fileinput.input():'和'for line in sys.stdin:'将在缓冲区中积累足够的字符后最终返回一些内容。如果fileinput传递了bufsize参数,那么你说它内部使用readlines()可能是正确的。 - Don Hatch
我刚刚提交了一个错误报告 http://bugs.python.org/issue26290,其中包括你所观察到的行为:“fileinput和'for line in sys.stdin'对输入缓冲做出奇怪的嘲弄”。总结:fileinput在2.7和3.4中都有问题,“for line in sys.stdin:”在2.7中有问题但在3.4中已修复,readline在2.7和3.4中都能正常工作。 - Don Hatch
2个回答

3

尝试运行python -u命令;man文档称这将“强制使标准输入、输出和错误流完全不带缓冲区”。

你可以直接修改filter.py文件第一行的hashbang路径。


1
Note that there is internal buffering in xreadlines(), readlines() and file-object iterators ("for line in sys.stdin") which is not influenced by this option. - tMC
是的,就像tMC所说的那样,这个方法行不通。虽然我尝试过了。 - John Zwinck
那么就不要使用基于行的I/O。使用普通的stdin.read() - 9000
1
readline()(单数)运行良好。只有readlines()(复数)会进行我不想要的缓冲。我想原始的read()也可以,但在这种情况下并不必要。 - John Zwinck

0

你尝试过了吗:

def hook_nobuf(filename, mode):
    return open(filename, mode, 0)

fi = fileinput.FileInput(openhook=hook_nobuf)

虽然我没有测试过,但是从阅读openhook参数的作用以及将bufsize参数传递0的含义来看,这应该可以解决问题。


1
这没有任何影响。再次出现问题似乎是因为fileinput使用了readlines()方法并在内部进行了缓冲。 - John Zwinck
好的,我认为这就是你的答案了。要么不使用fileinput,要么以fileinput.py为基础,重写它以避免内部缓冲。从代码来看,似乎没有任何方法可以通过传递参数来完全避免缓冲。 - John Gaines Jr.
2
我是Python的新手;令人震惊的是,这种用例并没有得到很好的覆盖(毕竟,在Python中编写文本过滤器似乎非常自然,如果不是因为这个)。 - John Zwinck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接