QPlainTextEdit 为大字符串消耗大量内存

QPlainTextEdit consume large memory for large string

我编写了一个小应用程序,其中字典包含大字符串,但是当我将字符串显示到 QPlainTextEdit 中时,它消耗大量内存,我的应用程序崩溃了。 有没有有效的更新文本到Qplaintextedit

size of string 464.6005735397339

Line #    Mem usage    Increment   Line Contents
================================================
   807   1556.8 MiB   1556.8 MiB       @profile
   808                                 def load_violation_data(self, a="", b=""):
   809                                     """
   810                                     update
   811                                     into.
   812                                     """
   813   1556.8 MiB      0.0 MiB           self.clear_selection()
   814   1556.8 MiB      0.0 MiB           domain_obj = self.list_widget.selectedItems()[0]
   815   1556.8 MiB      0.0 MiB           domain_obj.setBackground(QBrush(QColor("#8A2BE2")))
   816   1556.8 MiB      0.0 MiB           self.app.setOverrideCursor(Qt.WaitCursor)
   817   1556.8 MiB      0.0 MiB           data = self.violation_data[domain_obj.text()]
   818   1556.8 MiB      0.0 MiB           print (sys.getsizeof(data)/1024**2)
   819   4532.4 MiB   2975.6 MiB           self.plain_textedit.setPlainText(data)
   820   4532.4 MiB      0.0 MiB           self.violation_label.setText(self.vio_dm.get_output_file_prefix(domain_obj.text()))
   821   4532.4 MiB      0.0 MiB           self.app.restoreOverrideCursor()

在不知道文件结构的情况下,很难确定正确地分批分割数据的有效方法。

虽然概念基本相同:定义可加载数据的最大数量并且仅将文本设置为该数据的指定块。

在下面的示例中,查看器有一个默认的 5mb 限制(可以调整),它只是 搜索 文件光标位置到 limit×page,然后读取最大大小限制的内容并在纯文本编辑中显示它。

from PyQt5 import QtCore, QtGui, QtWidgets

class LargeFileView(QtWidgets.QWidget):
    def __init__(self, path=None, parent=None):
        super().__init__(parent)
        layout = QtWidgets.QVBoxLayout(self)
        tools = QtWidgets.QHBoxLayout()
        layout.addLayout(tools)

        style = self.style()
        self.startButton = QtWidgets.QToolButton(
            icon=style.standardIcon(style.SP_MediaSkipBackward))
        self.prevButton = QtWidgets.QToolButton(
            icon=style.standardIcon(style.SP_MediaSeekBackward))
        self.pageSpin = QtWidgets.QSpinBox(minimum=1, keyboardTracking=False)
        self.nextButton = QtWidgets.QToolButton(
            icon=style.standardIcon(style.SP_MediaSeekForward))
        self.endButton = QtWidgets.QToolButton(
            icon=style.standardIcon(style.SP_MediaSkipForward))
        self.sizeSpin = QtWidgets.QSpinBox(minimum=1, maximum=10, value=5, 
            suffix='MB', keyboardTracking=False)

        tools.addWidget(self.startButton)
        tools.addWidget(self.prevButton)
        tools.addWidget(self.pageSpin)
        tools.addWidget(self.nextButton)
        tools.addWidget(self.endButton)
        tools.addWidget(QtWidgets.QFrame(frameShape=QtWidgets.QFrame.VLine))
        limitLabel = QtWidgets.QLabel('Size limit:')
        tools.addWidget(limitLabel)
        limitLabel.setBuddy(self.sizeSpin)
        tools.addWidget(self.sizeSpin)
        tools.addStretch()

        font = QtGui.QFont()
        font.setFamily('monospace')
        self.plainTextEdit = QtWidgets.QPlainTextEdit(readOnly=True, font=font)
        layout.addWidget(self.plainTextEdit)

        self.pageSize = 5 * 1024 ** 2
        if path:
            self.loadFile(path)

        self.pageSpin.valueChanged.connect(lambda p: self.goToPage(p - 1))
        self.startButton.clicked.connect(lambda: self.goToPage(0))
        self.endButton.clicked.connect(lambda: self.goToPage(-1))
        self.prevButton.clicked.connect(lambda: self.stepBy(-1))
        self.nextButton.clicked.connect(lambda: self.stepBy(1))
        self.sizeSpin.valueChanged.connect(self._loadFile)

    def loadFile(self, path):
        if not QtCore.QFile.exists(path):
            return
        self.currentFile = QtCore.QFile(path)
        self.currentFile.open(QtCore.QIODevice.ReadOnly)
        self._loadFile()

    def _loadFile(self):
        self.currentPage = -1
        self.fileSize = self.currentFile.size()
        self.pageSize = self.sizeSpin.value() * 1024 ** 2
        self.pageCount = self.fileSize // self.pageSize + 1
        with QtCore.QSignalBlocker(self.pageSpin):
            self.pageSpin.setValue(1)
            self.pageSpin.setMaximum(self.pageCount)
            self.pageSpin.setSuffix(' / {}'.format(self.pageCount))
        self.goToPage(0)

    def stepBy(self, step):
        self.goToPage(self.currentPage + step)

    def goToPage(self, page):
        if page < 0:
            page = self.pageCount - 1
        if self.currentPage == page:
            return
        self.currentPage = page
        self.pageSpin.setValue(page + 1)
        if self.currentFile.seek(self.pageSize * page):
            text = str(self.currentFile.read(self.pageSize), 'utf-8')
            self.plainTextEdit.setPlainText(text)


app = QtWidgets.QApplication([])
test = LargeFileView('/your/very/big/file')
test.show()
app.exec()