私はかなり単純に聞こえることをやろうとしていますが、あらゆる種類の問題に遭遇し続けています. PyQt を使用して、同時に複数のファイルを追跡できる GUI を作成しようとしています。純粋なPythonでファイルを追跡する方法に関するこの回答を見ました
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 つの異なるファイルを追跡しようとします。0.1 秒のスリープを実行して、ループして 3 つのファイルに書き込む別のスクリプトを作成しました。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_())