首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >强制subprocess.Popen使用write()函数而不是fileno()将stdout/stderr写入python中类似文件的对象

强制subprocess.Popen使用write()函数而不是fileno()将stdout/stderr写入python中类似文件的对象
EN

Stack Overflow用户
提问于 2018-07-28 07:24:32
回答 2查看 757关注 0票数 1

我的目标是在python中使用subprocess.Popen打开一个进程,并让该进程将其stdout和stderr通过管道传递到我编写的自定义RingBuffer类,从而允许我从实例化该子进程的同一空间定期检查缓冲区的内容。这很重要,我知道有一些方法可以制作一个单独的程序,将子进程的输出通过管道传输到那个环形缓冲区程序的stdin中,但然后我必须手动检查一些包含环形缓冲区内容的底层文件,等等。理想的做法是将子进程的输出连接到我可以访问的某个对象。

首先,来自subprocess (Python2.x) (https://docs.python.org/2/library/subprocess.html)的文档

标准输入、标准输出和标准错误文件句柄分别指定执行程序的标准输入、标准输出和标准错误文件句柄。有效值包括PIPE、现有文件描述符(正整数)、现有文件对象和None。PIPE指示应该创建一个通向子对象的新管道。默认设置为“无”时,不会发生重定向;子文件句柄将从父文件句柄继承。此外,stderr可以是STDOUT,这表示应该将来自子进程的stderr数据捕获到与stdout相同的文件句柄中

“一个现有的文件对象”,所以我假设如果我创建一个符合file接口的类,它应该可以工作,对吧?

假设我做了一个这样的类

代码语言:javascript
复制
class RingBuffer(object):

    def __init__(max_size=1024*1024):
      self.max_size = max_size
      self.current_size = 0


    def write(self, data):
        self.current_size += len(data)
        self.data.append(data)
        if self.current_size >= self.max_size_bytes:
            while self.current_size >= self.trim_size_bytes:
                try:
                    popped = self.data.pop()
                    self.current_size -= len(popped)
                except IndexError as e:
                    break

def writelines(self, sequence):
    for item in sequence:
        self.write(item)

def dumps(self):
    ret = [line for line in self.data]
    return '\n'.join(ret)

def clear(self):
    self.data.clear()
    self.current_size = 0

假设这个程序中可能有错误,但你得到了要点,它公开了一个write()函数,并将数据写入循环缓冲区,当缓冲区出现太多错误时,将缓冲区修剪成特定的大小,并让用户在需要使用dumps()函数时恢复数据。

现在,如果我尝试这样的东西

代码语言:javascript
复制
r = RingBuffer()
pr = subprocess.Popen(["timeout", "15", "yes"], stdout=r, stderr=subprocess.STDOUT)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 382, in __init__
    errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
  File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 818, in _get_handles
    c2pwrite = stdout.fileno()
AttributeError: 'RingBuffer' object has no attribute 'fileno'

好了,我的“类文件”对象缺少符合文件接口的fileno()函数。这就是问题所在..为什么它需要一个fileno?为什么它不能直接使用我提供的write()函数呢?我假设它将绕过我的write函数,而不是使用fileno直接写入文件?

假设我添加了该函数存根

代码语言:javascript
复制
def fileno()
    return None

然后就会发生这种情况

代码语言:javascript
复制
r = RingBuffer()
pr = subprocess.Popen(["timeout", "15", "yes"], stdout=r, stderr=subprocess.STDOUT)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 390, in __init__
    errread, errwrite)
  File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1024, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

所以我的问题是:如何强制subprocess.Popen对我的file-like对象使用write()函数,而不是尝试直接写入从不存在的fileno()函数返回的文件句柄?如果没有办法做到这一点..有什么方法可以实现我想要的东西吗?

我知道从理论上讲,我可以创建一些文件,/tmp/ringlog.txt,并在实例化类时打开该文件,然后让程序写入该文件,让我的程序定期查看该文件,并使用类似的环形缓冲区算法将其保存在max_size下,但这很混乱。

另一种选择是编写一个程序,该程序读取stdin,写入文件,并对内容进行环缓冲,以使文件保持在一定的大小下,但我仍然要处理实际的文件,我只想将内容保存在内存中,并可从调用python的环境中访问。

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51566670

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档