在Python项目中实时捕获pygtk GUI的STDOUT输出
我正在做一个项目,想在一个用python和pygtk做的图形界面中使用命令行工具cdparanoia。我用Glade来开发界面。我试过导入subprocess模块,并使用subprocess.Popen来运行这个工具。虽然这样可以工作,但在这个过程中我的图形界面会卡住(连窗口都不能重新绘制),这对用户体验来说不好。我该怎么做才能避免这种情况呢?我想在窗口上放一个取消按钮,但因为程序“冻结”,这个按钮也没法用。最终,我希望能捕捉到错误信息(就像下面那样,音频信息通过标准输出传给sox),并把它展示在一个gtk.Expander里,样子类似于Synaptic在安装程序时的界面,让用户能实时看到发生的事情。此外,我还想用进度指示器中的文本(如下所示)来构建一个真正的进度指示器小部件。我该怎么做才能让shell实时把信息传回python,而不是等到过程结束后一次性给我所有信息呢?
需要捕捉的实时信息:
Working on me - me - DISK 01.flac
cdparanoia III release 10.2 (September 11, 2008)
Ripping from sector 0 (track 1 [0:00.00])
to sector 325195 (track 15 [1:56.70])
outputting to stdout
(== PROGRESS == [> | 004727 00 ] == :-) O ==)
这是我到目前为止使用的代码:
quick = " -Z" if self.quick == True else ""
command = "cdparanoia -w%s 1- -| sox -t wav - \"%s - %s - DISK %s%s.flac\"" %\
(
quick,
self.book_name.replace(" ", "_"),
self.author_name.replace(" ", "_"),
"0" if disc < 10 else "",
disc
)
print command
shell = subprocess.Popen(command, shell=True, executable="/bin/bash",
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
data, err = shell.communicate(command)
谢谢, Narnie
3 个回答
这里有两个问题。
第一个问题是,你需要设置一个读取超时时间,这样就不会一直等到子进程完成。
第二个问题是,可能会有一些不必要的缓冲发生。
为了处理第一个问题,如果你想异步地从子进程读取数据,可以试试我的 subProcess 模块,并设置一个超时时间:http://www.pixelbeat.org/libs/subProcess.py。需要注意的是,这个模块比较简单,但也比较旧,而且只适用于 Linux 系统。它是新 Python subprocess 模块的基础,所以如果你需要跨平台使用,还是建议使用那个。
如果你想了解或控制可能发生的额外缓冲,可以查看这个链接:http://www.pixelbeat.org/programming/stdio_buffering/
我曾经写过一个Python的命令行工具,它可以运行 wget
命令,还能显示实际的Python控制台输出,功能都很完整。
你需要使用 subprocess.Popen
,并且要直接写入 sys.stdout
:
process = subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
complete = False
while True:
output = process.stdout.read(1)
if output == '' and process.poll() != None:
break
if output != '':
sys.stdout.write(output)
sys.stdout.flush()