[英]subprocess.Popen stdin read file
我正在尝试在读取文件的一部分后调用文件的进程。 例如:
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 之前没有从 a 中读取任何内容,这将正常工作,但是如果我从中读取任何内容,则子流程将看不到任何内容。 这是使用 python 2.7.3。 我在文档中找不到任何解释这种行为的内容,并且(非常)简短地浏览了子流程源并没有发现原因。
如果您无缓冲地打开文件,则它可以工作:
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 行开头的位置。 由于预读缓冲区错误( io.open()
给出了预期的第 2 行位置),使用next(file)
而不是file.readline()
在我的 Python 2 机器上导致file.tell()
大约 5K。
在子file.seek(file.tell())
调用之前尝试file.seek(file.tell())
对具有默认基于 stdio 的文件对象的 Python 2 没有帮助。 它与 Python 2 上的io
、 _pyio
模块中的open()
函数以及 Python 3 上的默认open
(也是基于io
的)一起使用。
使用和不使用file.flush()
在 Python 2 和 Python 3 上尝试io
、 _pyio
模块会产生各种结果。 它确认在同一个文件描述符上混合缓冲和非缓冲 I/O 不是一个好主意。
这是因为子进程模块从文件对象中提取文件句柄。
http://hg.python.org/releasing/2.7.6/file/ba31940588b6/Lib/subprocess.py
在第 1126 行,来自 701。
文件对象使用缓冲区,并且在子进程提取文件句柄时已经从文件句柄中读取了很多内容。
正如@jfs 提到的,在使用 popen 时,它会将文件描述符传递给进程,同时 python 读取块(例如 4096 字节),结果是 fd 级别的位置与您期望的不同。
我通过对齐文件描述符位置在 python 2.7 中解决了它。
_file = open(some_path)
_file.read(codecs.BOM_UTF8)
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.