我正在尝试做听起来相当简单的事情,但我一直遇到各种各样的问题。我正在尝试创建一个可以使用 PyQt 同时跟踪多个文件的 GUI。我看到了这个关于如何在纯 Python 中跟踪文件的答案
我曾尝试在 QThread 中使用此代码。我在这里遇到的问题是尾部过程永远不会自行停止。它需要被杀死。当 GUI 关闭时,它应该被杀死。我在下面这个特定解决方案中遇到的其他问题是
QThread: Destroyed while thread is still running
和
QWaitCondition::wakeAll(): mutex lock failure:
和
QThread: Destroyed while thread is still running
Traceback (most recent call last):
File "./tailer.py", line 27, in run
self.emit(SIGNAL('newline'), line.rstrip())
RuntimeError: underlying C/C++ object has been deleted
我尝试过的其他实现有尾部进程抱怨管道损坏,但是一旦我做了 stderr=PIPE ,那些就停止出现了。我现在担心我可能会丢失错误,因为我从未从 stderr 读取过(因为它会阻塞并且不应该有任何输出)。
为了得到错误,尝试跟踪 3 个不同的文件。我编写了另一个脚本,该脚本循环并写入这 3 个文件,睡眠时间为 0.1 秒。我关闭 GUI 并一遍又一遍地启动它。有时我会出错,有时我不会。
请告诉我我在这里做错了什么。
#!/usr/bin/env python
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os
from subprocess import Popen, PIPE
class Tailer(QThread):
def __init__(self, fname, parent=None):
super(Tailer, self).__init__(parent)
self.fname = fname
self.connect(self, SIGNAL('finished()'), self.cleanup)
def cleanup(self):
print 'CLEANING UP'
self.p.kill()
print 'killed'
def run(self):
command = ["tail", "-f", self.fname]
print command
self.p = Popen(command, stdout=PIPE, stderr=PIPE)
while True:
line = self.p.stdout.readline()
self.emit(SIGNAL('newline'), line.rstrip())
if not line:
print 'BREAKING'
break
def foo(self):
self.p.kill()
class TailWidget(QWidget):
def __init__(self, fnames, parent=None):
super(TailWidget, self).__init__(parent)
layout = QGridLayout()
self.threads = {}
self.browsers = {}
for i, fname in enumerate(fnames):
if not os.path.exists(fname):
print fname, "doesn't exist; creating"
p = Popen(['touch', fname], stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
ret = p.wait()
assert ret == 0
t = Tailer(fname, self)
self.threads[fname] = t
b = QTextBrowser()
self.browsers[fname] = b
layout.addWidget(QLabel('Tail on %s' % fname), 0, i)
layout.addWidget(b, 1, i)
self.connect(t, SIGNAL("newline"), b.append)
t.start()
self.setLayout(layout)
def closeEvent(self, event):
for fname, t in self.threads.items():
t.foo()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
tw = TailWidget(sys.argv[1:])
tw.show()
sys.exit(app.exec_())