subprocess.Popen stdin读取文件

时间:2014-03-14 22:37:06

标签: 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)

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

3 个答案:

答案 0 :(得分:9)

如果您打开未缓冲的文件,那么它可以正常工作:

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的{​​{1}}模块,则可以重现该问题:

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)) 整除,则会输入更多输入。

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

bufsize=1报告所有缓冲区大小在第二行开头的位置。由于read-ahead buffer bugfile.tell()给出了预期的第二行位置),因此在我的机器上使用next(file)而不是file.readline()导致file.tell()大约5K。

在子进程调用之前尝试io.open()对于使用默认的基于stdio的文件对象的Python 2没有帮助。它适用于Python 2上的file.seek(file.tell())open()模块中的io函数以及Python 3上的默认_pyio(也基于open)。

使用和不使用io在Python 2和Python 3上尝试io_pyio模块会产生各种结果。它确认在同一文件描述符上混合缓冲和非缓冲I / O不是一个好主意

答案 1 :(得分:4)

这是因为子进程模块从文件对象中提取文件句柄。

http://hg.python.org/releasing/2.7.6/file/ba31940588b6/Lib/subprocess.py

第1126行,来自701。

文件对象使用缓冲区,并且在子进程提取时已经从文件句柄中读取了很多内容。

答案 2 :(得分:0)

我通过对齐文件描述符位置在python 2.7中解决了这个问题。

os.lseek(_file.fileno(), _file.tell(), os.SEEK_SET) truncate_null_cmd = ['tr','-d', '\\000'] subprocess.Popen(truncate_null_cmd, stdin=_file, stdout=subprocess.PIPE)