subprocess.Popen stdin读取文件

DRa*_*ayX 10 python subprocess

我试图在读取部分文件后调用文件上的进程.例如:

with open('in.txt', 'r') as a, open('out.txt', 'w') as b:
  header = a.readline()
  subprocess.call(['sort'], stdin=a, stdout=b)
Run Code Online (Sandbox Code Playgroud)

如果我在执行subprocess.call之前没有读取任何内容,这可以正常工作,但如果我从中读取任何内容,则子进程看不到任何内容.这是使用python 2.7.3.我在文档中找不到解释此行为的任何内容,并且(非常)简要地浏览一下子进程源并未显示原因.

jfs*_*jfs 10

如果你打开文件unbuffered然后它工作:

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

可以在没有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))
Run Code Online (Sandbox Code Playgroud)

如果缓冲区大小很小,则打印文件的其余部分:

#!/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))
Run Code Online (Sandbox Code Playgroud)

如果第一行大小不能被整除,它会占用更多输入bufsize.

默认bufsizebufsize=1(行缓冲)在我的机器上表现相似:文件的开头消失 - 大约4KB.

file.tell()报告所有缓冲区大小第二行开头的位置.由于预读缓冲区错误(给出预期的第二行位置),在Python 2上使用next(file)而不是file.readline()导致file.tell()我的机器上的导致大约5K .io.open()

file.seek(file.tell())在子进程调用之前尝试使用默认的基于stdio的文件对象对Python 2没有帮助.它与open()从函数io,_pyio对Python 2和与缺省的模块open(也io关于Python 3基).

尝试io,_pyio关于Python 2和Python 3的模块和不file.flush()产生不同的结果.它确认在同一文件描述符上混合缓冲和非缓冲I/O并不是一个好主意.