python StringIO 不能作为带有 subrprocess.call() 的文件

ale*_*kot 8 python console file stringio

我正在使用subprocess包从 python 脚本调用一些外部控制台命令,我需要将文件处理程序传递给它以分别返回stdoutstderr。代码大致如下:

import subprocess

stdout_file = file(os.path.join(local_path, 'stdout.txt'), 'w+')
stderr_file = file(os.path.join(local_path, 'stderr.txt'), 'w+')

subprocess.call(["somecommand", "someparam"], stdout=stdout_file, stderr=stderr_file)
Run Code Online (Sandbox Code Playgroud)

这工作正常,并且正在创建具有相关输出的 txt 文件。然而,在忽略文件创建的内存中处理这些输出会更好。所以我使用 StringIO 包来处理它:

import subprocess
import StringIO

stdout_file = StringIO.StringIO()
stderr_file = StringIO.StringIO()

subprocess.call(["somecommand", "someparam"], stdout=stdout_file, stderr=stderr_file)
Run Code Online (Sandbox Code Playgroud)

但这不起作用。失败:

  File "./test.py", line 17, in <module>
    subprocess.call(["somecommand", "someparam"], stdout=stdout_file, stderr=stderr_file)
  File "/usr/lib/python2.7/subprocess.py", line 493, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 672, in __init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
  File "/usr/lib/python2.7/subprocess.py", line 1063, in _get_handles
    c2pwrite = stdout.fileno()
AttributeError: StringIO instance has no attribute 'fileno'
Run Code Online (Sandbox Code Playgroud)

我看到它缺少本机文件对象的某些部分并因此失败。

所以这个问题比实际更具教育意义 - 为什么 StringIO 中缺少文件接口的这些部分,是否有任何原因无法实现?

Van*_*pps 10

正如您在评论中所说,PopenPopen.communicate是这里正确的解决方案。

一点背景知识:真实的文件对象具有文件描述符,这是对象所缺少的fileno属性。StringIO它们只是普通的整数:您可能熟悉文件描述符 0、1 和 2,它们分别是stdinstdoutstderr。如果一个进程打开了更多文件,它们会被分配 3、4、5 等。您可以使用 来查看进程的当前文件描述符lsof -p

那么,为什么对象不能StringIO有文件描述符呢?为了获得一个,它需要打开一个文件或打开一个管道*。打开文件没有意义,因为打开文件才是使用的全部目的StringIO

打开管道也没有意义,即使它们像StringIO对象一样存在于内存中。它们用于通信,而不是存储:seektruncatelen对于管道来说根本没有任何意义,并且其行为readwrite对于文件的行为非常不同。当您read从管道中删除返回的数据时,将从管道的缓冲区中删除,如果当您尝试删除该(相对较小的)缓冲区已满时write,您的进程将挂起,直到read从管道中删除某些内容以释放缓冲区空间。

因此,如果您想将字符串用作stdinstdout用于stderr子进程,则StringIO不会削减它,但它Popen.communicate是完美的。如上所述(并在subprocess文档中警告过),正确读取和写入管道很复杂。Popen为您处理这种复杂性。

* 我想我理论上可以想象第三种文件描述符对应于进程之间共享的内存区域?不太确定为什么不存在。但是,呃,我不是内核开发人员,所以我确信这是有原因的。

  • [文档](https://docs.python.org/3.6/library/subprocess.html#frequently-used-arguments)具有误导性。它说 `stdout` 的值可以是“*现有的[文件对象](https://docs.python.org/3.6/glossary.html#term-file-object)*”,没有提到它需要文件对象有一个“fileno”。 (3认同)

Fre*_*ell -3

我认为您期望其他进程知道如何从主进程中以流的形式读取内存。也许如果您可以将流传输到标准输入并将标准输出传输到流中,您可能会成功。