当前位置:   C++ > 正文

如何从Qt中的大文件异步加载数据?

c++,io,qt,multithreading,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳,在线开发工具,前端开发工具,开发人员工具,站长工具

我正在使用Qt 5.2.1来实现一个程序,该程序从文件中读取数据(可能是几个字节到几GB),并以依赖于每个字节的方式显示数据.我的例子是一个十六进制查看器.

一个对象执行读取,并dataRead()在读取新数据块时发出信号.信号带有一个指向QByteArray类似的指针,所以:

filereader.cpp

void FileReader::startReading()
{

    /* Object state code here... */

        {
            QFile inFile(fileName);

            if (!inFile.open(QIODevice::ReadOnly))
            {
                changeState(STARTED, State(ERROR, QString()));
                return;
            }

            while(!inFile.atEnd())
            {
                QByteArray *qa = new QByteArray(inFile.read(DATA_SIZE));
                qDebug() << "emitting dataRead()";
                emit dataRead(qa);
            }
        }

    /* Emit EOF signal */

}

查看器的loadData插槽连接到此信号,这是显示数据的功能:

hexviewer.cpp

void HexViewer::loadData(QByteArray *data)
{
    QString hexString = data->toHex();

    for (int i = 0; i < hexString.length(); i+=2)
    {
        _ui->hexTextView->insertPlainText(hexString.at(i));
        _ui->hexTextView->insertPlainText(hexString.at(i+1));
        _ui->hexTextView->insertPlainText(" ");
    }

    delete data;
}

第一个问题是如果这只是按原样运行,GUI线程将完全没有响应.dataRead()在重新绘制GUI之前,将发出所有信号.

(可以运行完整代码,当您使用大于1kB的文件时,您将看到此行为.)

通过对我的论坛的回复发布Qt5中的非阻塞本地文件IO以及另一个Stack Overflow问题的答案如何在qt中执行异步文件io?,答案是:使用线程.但这些答案都没有详细说明如何改变数据本身,也不知道如何避免常见的错误和陷阱.

如果数据很小(大约一百字节)我只是用信号发出它.但是如果文件的大小是GB(编辑),或者文件是基于网络的文件系统,例如.NFS,Samba共享,我不希望UI只是因为读取文件块而锁定.

第二个问题是new在发射器和delete接收器中使用的机制看起来有点幼稚:我实际上是将整个堆用作跨线程队列.

问题1:在限制内存消耗的同时,Qt是否有更好/惯用的方式跨线程移动数据?它是否有一个线程安全队列或其他可以简化整个事情的结构?

问题2:我自己是否必须实施线程等?我不是重塑轮子的忠实粉丝,特别是在内存管理和线程方面.是否有更高级别的构造可以做到这一点,就像网络传输一样?



1> hank..:

首先,您的应用程序中根本没有任何多线程.您的FileReader类是其子类QThread,但并不意味着所有FileReader方法都将在另一个线程中执行.实际上,所有操作都在主(GUI)线程中执行.

FileReader应该是一个QObject而不是一个QThread子类.然后,您创建一个基本QThread对象,并使用您的工作者(读者)移动它QObject::moveToThread.你可以在这里阅读这个技术.

确保您已FileReader::State使用注册类型qRegisterMetaType.这对于Qt信号槽连接在不同线程上工作是必要的.

一个例子:

HexViewer::HexViewer(QWidget *parent) :
    QMainWindow(parent),
    _ui(new Ui::HexViewer),
    _fileReader(new FileReader())
{
    qRegisterMetaType("FileReader::State");

    QThread *readerThread = new QThread(this);
    readerThread->setObjectName("ReaderThread");
    connect(readerThread, SIGNAL(finished()),
            _fileReader, SLOT(deleteLater()));
    _fileReader->moveToThread(readerThread);
    readerThread->start();

    _ui->setupUi(this);

    ...
}

void HexViewer::on_quitButton_clicked()
{
    _fileReader->thread()->quit();
    _fileReader->thread()->wait();

    qApp->quit();
}

此外,没有必要在堆上分配数据:

while(!inFile.atEnd())
{
    QByteArray *qa = new QByteArray(inFile.read(DATA_SIZE));
    qDebug() << "emitting dataRead()";
    emit dataRead(qa);
}

QByteArray使用隐式共享.这意味着当您QByteArray以只读模式跨函数传递对象时,不会反复复制其内容.

将上面的代码更改为此,忘记手动内存管理:

while(!inFile.atEnd())
{
    QByteArray qa = inFile.read(DATA_SIZE);
    qDebug() << "emitting dataRead()";
    emit dataRead(qa);
}

但无论如何,主要问题不在于多线程.问题是QTextEdit::insertPlainText操作并不便宜,尤其是当您拥有大量数据时.FileReader快速读取文件数据,然后使用要显示的新数据部分填充窗口小部件.

必须注意的是,你的实现非常无效HexViewer::loadData.您可以通过char插入文本数据char,这会QTextEdit不断重绘其内容并冻结GUI.

您应该首先准备生成的十六进制字符串(请注意,数据参数不再是指针):

void HexViewer::loadData(QByteArray data)
{
    QString tmp = data.toHex();

    QString hexString;
    hexString.reserve(tmp.size() * 1.5);

    const int hexLen = 2;

    for (int i = 0; i < tmp.size(); i += hexLen)
    {
        hexString.append(tmp.mid(i, hexLen) + " ");
    }

    _ui->hexTextView->insertPlainText(hexString);
}

无论如何,您的应用程序的瓶颈不是文件读取,而是QTextEdit更新.按块加载数据然后将其附加到窗口小部件QTextEdit::insertPlainText将不会加快任何速度.对于小于1Mb的文件,一次读取整个文件然后在一个步骤中将结果文本设置为窗口小部件会更快.

我想你不能使用默认的Qt小部件轻松地显示大于几兆字节的巨大文本.此任务需要一些非平凡的approch,通常与多线程或异步数据加载无关.这一切都是关于创建一些棘手的小部件,它不会试图立即显示其巨大的内容.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/CPP/detail/13979
推荐阅读
  • 如何解决《grailsspring安全角色和组》经验,为你挑选了0个好方法。grails,spring-security,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳... [详细]

  • 如何解决《用户无权执行:cloudformation:CreateStack》经验,为你挑选了3个好方法。amazon-web-services,amazon-cloudformation,amazon-iam,服务器,安全,DevBox,... [详细]

  • 如何解决《在Swift3中仅修剪字符串末尾的空格》经验,为你挑选了5个好方法。string,swift,swift3,go,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间... [详细]

  • 如何解决《Chrome扩展程序:检查是否已注入内容脚本》经验,为你挑选了1个好方法。javascript,google-chrome,google-chrome-extension,chrome,json,注入,go,安全,css,DevB... [详细]

  • 如何解决《获取两个size_t对象的区别是否安全?》经验,为你挑选了2个好方法。c++,size-t,ios,安全,https,go,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix... [详细]

  • 如何解决《禁用ASP.NETEventValidation》经验,为你挑选了1个好方法。.net,asp.net,eventvalidation,安全,javascript,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发... [详细]

  • 如何解决《为什么这个scanf会导致分段错误?》经验,为你挑选了1个好方法。c,struct,scanf,segmentation-fault,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维... [详细]

  • 如何解决《如何在Rust中运行时分配数组?》经验,为你挑选了2个好方法。memory,allocation,dynamic,rust,算法,安全,go,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二... [详细]

  • 如何解决《使用@EnableCaching的SpringBoot默认缓存管理器》经验,为你挑选了1个好方法。caching,spring-boot,spring-cache,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具... [详细]

  • 如何解决《我什么时候应该使用subprocess.Popen而不是os.popen?》经验,为你挑选了1个好方法。python,subprocess,popen,windows,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者... [详细]

  • 如何解决《安全忽略Carthage.resolved?》经验,为你挑选了1个好方法。ios,carthage,git,安全,bootstrap,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成... [详细]

  • 如何解决《'Classname<T>,T:Classname<T>'的作用是什么?》经验,为你挑选了1个好方法。c#,generics,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工... [详细]

  • 如何解决《如何使用目标向量对data.table进行排序》经验,为你挑选了1个好方法。r,data.table,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳,在线开发... [详细]

  • 如何解决《SQL要求声明声明的变量》经验,为你挑选了1个好方法。tsql,sql-server-2008,sql,安全,注入,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳,... [详细]

  • 如何解决《将原始字节数组复制到空字节向量的最有效方法》经验,为你挑选了1个好方法。c++,stl,vector,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳,在线开发... [详细]

  • 如何解决《开发人员测试与QA团队测试-什么是正确的工作分工?》经验,为你挑选了3个好方法。testing,unit-testing,qa,process,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json... [详细]

  • 如何解决《WinDbg中的_invoke_watson是什么?》经验,为你挑选了1个好方法。c++,windbg,安全,windows,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,uni... [详细]

  • 如何解决《避免使用NavigatorUserMediaError"Chrome中的HTTP只允许安全来源"》经验,为你挑选了1个好方法。media,security,https,google-chrome,javascr... [详细]

  • 如何解决《C++static_castvsdynamic_cast》经验,为你挑选了1个好方法。c++,安全,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳,在线开发工具,前... [详细]

  • 如何解决《在机器人框架中安全地从字典中获取密钥》经验,为你挑选了1个好方法。robotframework,安全,lua,python,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix... [详细]

相关标签
  

闽ICP备14008679号