我的目标是在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
接口的类,它应该可以工作,对吧?
假设我做了一个这样的类
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()
函数时恢复数据。
现在,如果我尝试这样的东西
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
直接写入文件?
假设我添加了该函数存根
def fileno()
return None
然后就会发生这种情况
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的环境中访问。
https://stackoverflow.com/questions/51566670
复制相似问题