Сбой программы при отслеживании файла, который быстро обновляется - PullRequest
0 голосов
/ 30 октября 2019

Цель моей программы - создать файл, который обновляется, возможно, сотнями строк кода каждую секунду, и добавлять каждую строку в текстовое поле PyQt4 в графическом интерфейсе. При запуске моего кода Python, который привязывает пару файлов и выводит каждую строку в текстовое поле QtPy, моя программа аварийно завершает работу при каждом добавлении пакета строк к указанным файлам.

До сих пор я пытался реализовать таймер ожидания time.sleep(1) внутри цикла while, который добавляет каждую хвостатую строку в текстовое поле. Однако может показаться, что я достигаю переполнения буфера или ограничения кеша, потому что, хотя это работает с тем, как часто обновляется текстовое поле, когда я получаю пакет строк, добавленных в хвостовой файл, моя программа по-прежнему аварийно завершает работу.

import sys, os, PyQt4, subprocess, time, threading
shouldRun = True
def tailFile():
    file1 = subprocess.Popen(['tail', '-F', 'FILENAME1', stdout=subprocess.PIPE, preecec_fn=os.setsid)
    poll1 = select.poll()
    poll1.register(file1.stdout)

    file2 = subprocess.Popen(['tail', '-F', 'FILENAME2', stdout=subprocess.PIPE, preecec_fn=os.setsid)
    poll2 = select.poll()
    poll2.register(file2.stdout)

    while shouldRun:
        textbox01.append(file1.stdout.readline())
        textbox02.append(file2.stdout.readline())
        #time.sleep(1)
    return


runTailing = threading.Thread(target = tailFile)
runTailing.start()

Мои единственные обнаруженные ошибки:

QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
ASSERT failure in QVector<T>::operator[]: "index out of range"

1 Ответ

0 голосов
/ 30 октября 2019

Поскольку вы не предоставляете MRE, трудно точно указать, где находится ошибка, и, следовательно, дать решение на основе вашего кода. Но из сообщения об ошибке видно, что вы пытаетесь добавить информацию в графический интерфейс напрямую через метод добавления, и это запрещено в Qt, в этих случаях лучшим вариантом является использование сигналов.

Мое решение идетпо-другому, так как я предлагаю использовать QProcess, который позволяет выполнять tail без необходимости создавать другой поток, уведомляющий с помощью сигнала о новой информации:

import os
import sys

from PyQt4 import QtCore, QtGui


class FileMonitor(QtCore.QObject):
    fileChanged = QtCore.pyqtSignal(str)

    def __init__(self, filename, parent=None):
        super().__init__(parent)
        self._filename = filename
        self._process = QtCore.QProcess(self)
        self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)

    @property
    def filename(self):
        return self._filename

    def start(self):
        self._process.start("tail", ["-F", self.filename])

    def _on_readyReadStandardOutput(self):
        text = self._process.readAllStandardOutput().data().decode()
        self.fileChanged.emit(text)


class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.textbox01 = QtGui.QTextEdit(readOnly=True)
        self.textbox02 = QtGui.QTextEdit(readOnly=True)

        lay = QtGui.QHBoxLayout(self)
        lay.addWidget(self.textbox01)
        lay.addWidget(self.textbox02)

        current_dir = os.path.dirname(os.path.realpath(__file__))
        filenames = [
            os.path.join(current_dir, "FILENAME1"),
            os.path.join(current_dir, "FILENAME2"),
        ]
        for filename, textbox in zip(filenames, (self.textbox01, self.textbox02)):
            monitor = FileMonitor(filename, self)
            monitor.fileChanged.connect(textbox.append)
            monitor.start()


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())
...