如果你打开没有缓冲的文件,那么它可以工作:
import subprocess
with open('in.txt', 'rb', 0) as a, open('out.txt', 'w') as b:
header = a.readline()
rc = subprocess.call(['sort'], stdin=a, stdout=b)
subprocess 模块在文件描述符级别(操作系统的低级别无缓冲 I/O)工作。如果操作系统支持,它可以与os.pipe()、socket.socket()、pty.openpty() 以及任何具有有效.fileno() 方法的东西一起使用。
不建议在同一个文件中混合使用缓冲和非缓冲 I/O。
在 Python 2 上,file.flush() 导致输出出现,例如:
import subprocess
# 2nd
with open(__file__) as file:
header = file.readline()
file.seek(file.tell()) # synchronize (for io.open and Python 3)
file.flush() # synchronize (for C stdio-based file on Python 2)
rc = subprocess.call(['cat'], stdin=file)
在没有subprocess 模块和os.read() 的情况下可以重现该问题:
#!/usr/bin/env python
# 2nd
import os
with open(__file__) as file: #XXX fully buffered text file EATS INPUT
file.readline() # ignore header line
os.write(1, os.read(file.fileno(), 1<<20))
如果缓冲区很小,则打印文件的其余部分:
#!/usr/bin/env python
# 2nd
import os
bufsize = 2 #XXX MAY EAT INPUT
with open(__file__, 'rb', bufsize) as file:
file.readline() # ignore header line
os.write(2, os.read(file.fileno(), 1<<20))
如果第一行大小不能被bufsize 整除,它会消耗更多输入。
默认的 bufsize 和 bufsize=1(行缓冲)在我的机器上表现相似:文件的开头消失了——大约 4KB。
file.tell() 报告所有缓冲区大小的第 2 行开头的位置。由于read-ahead buffer bug,使用next(file) 而不是file.readline() 在我的Python 2 上的机器上导致file.tell() 大约5K(io.open() 给出了预期的第二行位置)。
在子进程调用之前尝试file.seek(file.tell()) 对 Python 2 的默认基于 stdio 的文件对象没有帮助。它适用于 Python 2 上来自 io、_pyio 模块的 open() 函数以及 Python 3 上的默认 open(也基于 io)。
在 Python 2 和 Python 3 上尝试io、_pyio 模块,无论是否使用file.flush(),都会产生各种结果。它确认在同一个文件描述符上混合缓冲和非缓冲 I/O 不是一个好主意。