繁体   English   中英

subprocess.Popen 标准输入读取文件

[英]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整除,它会消耗更多的输入。

默认的bufsizebufsize=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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM