首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > QT开发 >

多线程加载大文件到QTextEdit中,该如何处理

2012-12-16 
多线程加载大文件到QTextEdit中我要加载一个大文件到QTextEdit中,就是在其他线程打开文件读取,然后写入到Q

多线程加载大文件到QTextEdit中
我要加载一个大文件到QTextEdit中,
就是在其他线程打开文件读取,然后写入到QTextEdit中去。
这样就不会导致main GUI线程无法响应。
1.  但是其他线程不能调用GUI元素啊。有什么好的办法吗?谢谢。
2.  我现在是想用readLine,这样一行一行读入,然后QTextEdit::append这样写入的。这样是否合适?谢谢
[最优解释]

引用:
别用Qstring
就用QFile read
然后按需读取  
你这样相当于把所有的文件全部加载进来 内存占的肯定比较大  而且估计QString不适合放这么多数据吧
这意味着QString每次当capacity不够时 要重新resize 然后拷贝原来的数据

readall不可以吗?一次读进QString。
[其他解释]
个人感觉readAll会触发构造多个QString对象
每个QString对象在capacity()不够时  会重新resize 然后拷贝原来的数据 相当于构造了多次
对几十K的数据应该没问题 上10M的估计会多次resize

引用:
引用:
别用Qstring
就用QFile read
然后按需读取  
你这样相当于把所有的文件全部加载进来 内存占的肯定比较大  而且估计QString不适合放这么多数据吧
这意味着QString每次当capacity不够时 要重新resize 然后拷贝原来的数据
readall不可以吗?一次读进QString。

[其他解释]
其实读文件不要很多时间,完全是显示费时间,可以具体测试一下读文件用多少时间(读取到一个QString里)。
[其他解释]
class workThread: public QThread
{
Q_OBJECT
signals:
   void signal_read_done(QByteArray & data);
private:
   void run();
}
新创建一个workThread,在workThread里读取大文件。读取完毕的时候 emit signal_read_done,然后在界面线程里做slot,读取数据
[其他解释]
引用:
class workThread: public QThread
{
Q_OBJECT
signals:
   void signal_read_done(QByteArray & data);
private:
   void run();
}
新创建一个workThread,在workThread里读取大文件。读取完毕的时候 emit sign……


我也想过这个样子。但是对于几十M的文件,这样读取我不知道QString会不会有问题。
[其他解释]
别用Qstring
就用QFile read
然后按需读取  
你这样相当于把所有的文件全部加载进来 内存占的肯定比较大  而且估计QString不适合放这么多数据吧
这意味着QString每次当capacity不够时 要重新resize 然后拷贝原来的数据
[其他解释]
引用:
别用Qstring
就用QFile read
然后按需读取  
你这样相当于把所有的文件全部加载进来 内存占的肯定比较大  而且估计QString不适合放这么多数据吧
这意味着QString每次当capacity不够时 要重新resize 然后拷贝原来的数据

我现在就是一行一行读取的啊。
我做在其他线程,就无法调用QTextEdit来插入了。
[其他解释]
引用:
引用:
别用Qstring
就用QFile read
然后按需读取  
你这样相当于把所有的文件全部加载进来 内存占的肯定比较大  而且估计QString不适合放这么多数据吧
这意味着QString每次当capacity不够时 要重新resize 然后拷贝原来的数据
我现在就是一行一行读取的啊。
我做在其他线程,就无法调用QTextEdit来插入了。……


之前已经说了
你在其他线程处理完了 然后产生响应的事件 在QTextEdit中捕获这个signal 驱动响应的slot完成所有的操作
你不要直接在QTextEdit里操作  实际上非界面线程直接操作 GUI是非线程安全的
用signal - slot来完成

[其他解释]
引用:
个人感觉readAll会触发构造多个QString对象
每个QString对象在capacity()不够时  会重新resize 然后拷贝原来的数据 相当于构造了多次
对几十K的数据应该没问题 上10M的估计会多次resize



引用:引用:
别用Qstring
就用QFile read
然后按需……


还是开始的话:读文件不是问题,关键是显示慢。
[其他解释]
有可能
显示可以做增量显示
读出来1MB 就显示一次

引用:
引用:
个人感觉readAll会触发构造多个QString对象
每个QString对象在capacity()不够时  会重新resize 然后拷贝原来的数据 相当于构造了多次
对几十K的数据应该没问题 上10M的估计会多次resize

引用:引用:
别用Qstring
就用QFile r……

[其他解释]
刚测试完,结果:一个2376KB的文本文件,读取用80ms,显示出来用2150ms。
如果只是显示无格式文本,用QPlainTextEdit能明显加快。
[其他解释]
不错
学习了
引用:
刚测试完,结果:一个2376KB的文本文件,读取用80ms,显示出来用2150ms。
如果只是显示无格式文本,用QPlainTextEdit能明显加快。

[其他解释]
引用:
个人感觉readAll会触发构造多个QString对象
每个QString对象在capacity()不够时  会重新resize 然后拷贝原来的数据 相当于构造了多次
对几十K的数据应该没问题 上10M的估计会多次resize

引用:引用:
别用Qstring
就用QFile read
然后按需……


那这样的话只能读取1M到QString中,然后发射信号到slot中由main线程去插入到textedit中去。
是吧?
[其他解释]
QFile 
先read 1M数据
然后seek到1M
emit 这1M的数据到QTextEdit显示
再read 1M 
seek到2M
emit 1M显示
[其他解释]
引用:
QFile 
先read 1M数据
然后seek到1M
emit 这1M的数据到QTextEdit显示
再read 1M 
seek到2M
emit 1M显示


恩,谢谢。
[其他解释]
引用:
有可能
显示可以做增量显示
读出来1MB 就显示一次

引用:引用:
个人感觉readAll会触发构造多个QString对象
每个QString对象在capacity()不够时  会重新resize 然后拷贝原来的数据 相当于构造了多次
对几十K的数据应该没问题 上10M的估计会多次resize
……


我觉得这存在一个同步的问题,读取文件块,然而显示到gui中却很慢。
那么这样子会导致读取文件线程一直在等待主线程。
另外,QString这个类那应该new出来吧,不然栈区能存储得了吗?
谢谢


[其他解释]
引用:
其实中间用QString完全是多余,只是为了测试。
完全可以readall,一次读进来放进edit。
我测试了:读文件用80ms,显示出来用2150ms(函数运行完了),其实还没看见窗口,还要一会窗口才会出来。
显示大文件的edit基本上都是自己实现的。


我这些文件非常大。你说用readAll,这样一次性加载那么多数据到内存中,会占用很大的。
我想用楼上那兄弟说得在其他线程中一次读取1M,这样一次一次的读取。
在workThread的run中进行同步,用QMutex。
[其他解释]
其实中间用QString完全是多余,只是为了测试。
完全可以readall,一次读进来放进edit。
我测试了:读文件用80ms,显示出来用2150ms(函数运行完了),其实还没看见窗口,还要一会窗口才会出来。
显示大文件的edit基本上都是自己实现的。
[其他解释]
引用:
还是自己实现edit吧,现成的控件满足不了要求。
不管一次读取多少文本,最后呢?如果不是自己实现edit分段显示,还不是全部文本放进内存里了。

恩,不过分段显示没坐过这个。你做过吗?
应该很麻烦吧。
[其他解释]
还是自己实现edit吧,现成的控件满足不了要求。
不管一次读取多少文本,最后呢?如果不是自己实现edit分段显示,还不是全部文本放进内存里了。
[其他解释]
我试了试
jdwx1说的很对 显示慢 读还行 速度不是瓶颈
我用下面的方法写了写 UI基本上不会卡 反正可以看到QTextEdit一直在加载数据


我每次读进来的数据用signal传出去 用Qt的signal-slot做了数据拷贝 因此读完之后直接释放了
如果不用界面显示的话 内存很小 大概4,5M左右
用界面显示的话 内存就比较大了
我这里没有写同步的机制  其实你可以
 两个线程互相控制
readThread 读完了通知主界面显示
主界面显示完了 通知readThread 继续读
我这里sleep了 读个20M的文本 不会卡死界面
void 
readThread::run()
{
    QFileInfo info(mFileURL);
    if ( false == info.exists())
    {
        qDebug()<<"file not exist";
        return ;
    }
    qint64 fileSize = info.size();
    QFile theFile(mFileURL);
    if (!theFile.open(QIODevice::ReadOnly))
    {
        return;
    }
    if ( fileSize < 1024 * 1024 ) //小于1M就全部读取
    {
        QByteArray & buffer = theFile.readAll();
        qDebug("readThread::run %p\n",&buffer);
        emit signal_buffer_read(buffer);
        buffer.clear();
        theFile.close();
    }   
    else
    {
        int readNumberCnt = 0;
        int loopNumber = fileSize /( 64 * 1024);
        int leftSize = fileSize % ( 64 * 1024);
        for ( int i = 0 ; i < loopNumber ; i ++ )
        {
             QByteArray & buffer = theFile.read(64*1024);
             emit signal_buffer_read(buffer);
             Q_ASSERT( true == theFile.seek(64*1024* (i+1)));
             readNumberCnt += buffer.size();
             qDebug()<< "readThread "<<theFile.pos();
             QThread::msleep(200);
             buffer.clear();
        }
        if ( leftSize )
        {
            QByteArray & buffer = theFile.read(leftSize);
            qDebug("readThread::run %p\n",&buffer);
            emit signal_buffer_read(buffer);
            readNumberCnt += buffer.size();
            buffer.clear();
        }


        Q_ASSERT(readNumberCnt == fileSize );
        theFile.close();
    }
}
[其他解释]
也没做过,不过可以考虑找一个开源的edit看看源码(scite)。
或者找一个开源的edit控件。
[其他解释]

引用:
我试了试
jdwx1说的很对 显示慢 读还行 速度不是瓶颈
我用下面的方法写了写 UI基本上不会卡 反正可以看到QTextEdit一直在加载数据
我每次读进来的数据用signal传出去 用Qt的signal-slot做了数据拷贝 因此读完之后直接释放了
如果不用界面显示的话 内存很小 大概4,5M左右
用界面显示的话 内存就比较大了
我这里没有写同步的机制  ……


非常感谢你。我考虑的是若是100M的文件,那么单纯QTextEdit加载显示进去就要100M来存储那些字符。
所以只能做分段显示。
另外,你的代码sleep这样子行的通吗?你不能确定他能在200毫秒里面显示完啊。
所以我觉得用QWaitCondition来做,当gui显示完了,就QWaitCondition.wakeAll(),读取线程发送完信号后就wait,等待gui线程的wakeAll。
这样子应该没问题吧。
[其他解释]
做显示的难点在于按需显示
你可以看看word 启动时 不是所有的数据都显示
而是到当前界面时 再加载数据
写一个完备的edit难度很大 
你每次读64K  然后sleep一下 基本不会卡死界面
[其他解释]
引用:
引用:引用:
我试了试
jdwx1说的很对 显示慢 读还行 速度不是瓶颈
我用下面的方法写了写 UI基本上不会卡 反正可以看到QTextEdit一直在加载数据
我每次读进来的数据用signal传出去 用Qt的signal-slot做了数据拷贝 因此读完之后直接释放了
如果不用界面……

用到100M是我猜的,我没试。我意思是:读100M数据显示到QTextEdit中,那么QTextEdit肯定最少也的要100M内存啊。
[其他解释]
引用:
引用:
我试了试
jdwx1说的很对 显示慢 读还行 速度不是瓶颈
我用下面的方法写了写 UI基本上不会卡 反正可以看到QTextEdit一直在加载数据
我每次读进来的数据用signal传出去 用Qt的signal-slot做了数据拷贝 因此读完之后直接释放了
如果不用界面显示的话 内存很小 大概4,5M左右
用界面显示的话 内存就比较大了
我这里……


恩 我前面的同步写的比较简单 直接用sleep来的 你可以考虑用wait来同步
我如果不在界面显示 只在界面线程答应buffer 读12M的数据 最后运行完了 大概只占用4MB
说明读的地方没内存泄露
但是要在界面显示 内存居然到了100多MB 所以我觉得QTextedit在后台做了很多数据拷贝 
[其他解释]
其实我没懂你的意思,是要加载一个大文件GUI不被卡住,还是要想某些成品的编辑器一样能处理任意大的文本?不过像是第一个要求。

[其他解释]
引用:
也没做过,不过可以考虑找一个开源的edit看看源码(scite)。
或者找一个开源的edit控件。


还是要麻烦你帮忙看下代码,我搞运维的所以qt不怎么懂。
下面是刚写的线程类。我觉得还是有些问题。
1. 你读取64kb的话,那么存在可能将一个字符截断。因为在QTextEdit是用append的,那么他会自动加一个换行符,这样就将一个字符给显示错了。
2. 下面这小段是我在gui中的,若用户点击关闭按钮则调用thread中的stop函数,然后等待thread的结束,
这样写有没有问题呢?我在thread的stop中直接调用terminal的,这个没问题吧?
谢谢
void MainWindow::closeEvent(QCloseEvent *event)
{
    if(myThread->isRunning())
        myThread->stop();
    myThread->wait();
    event->accept();
}



---------------------------------------------

class MyThread:public QThread
{
    Q_OBJECT
public:
    MyThread(QObject *parent=0):QThread(parent)
    {
    }
    void setParams(const QString *PfilePath,QByteArray *PreadData,QWaitCondition *PreadWait,QMutex *Pmutex)
    {
        filePath = *PfilePath;


        readData = PreadData;
        readWait = PreadWait;
        mutex = Pmutex;
    }
    void stop()
    {
        mutex->unlock();
        this->terminate();
    }
signals:
    void loadOk();
private:
    QString filePath;
    QByteArray *readData;
    QWaitCondition *readWait;
    QMutex *mutex;

protected:
    void run()
    {
        QFileInfo info(filePath);
        if( false == info.exists() )
            return;
        qint64 fileSize = info.size();
        QFile file(filePath);
        if(!file.open(QFile::ReadOnly))
            return;
        if(fileSize < 1024*1024 )
        {
            *readData = file.readAll();
            emit loadOk();
        } else {
            int loop = fileSize /(64*1024);
            int leftSize = fileSize%(64*1024);
            for(int i=0;i<loop;i++)
            {
                mutex->lock();
                *readData = file.read(64*1024);
                emit loadOk();
                readWait->wait(mutex);
                mutex->unlock();
            }
            if(leftSize)
            {
                *readData = file.read(leftSize);
                emit loadOk();
            }
        }
        file.close();
    }
};
[其他解释]

引用:
其实我没懂你的意思,是要加载一个大文件GUI不被卡住,还是要想某些成品的编辑器一样能处理任意大的文本?不过像是第一个要求。



1. 你读取64kb的话,那么存在可能将一个字符截断。因为在QTextEdit是用append的,那么他会自动加一个换行符,这样就将一个字符给显示错了。
这是我搞错了。不会截断。呵呵
[其他解释]
gui不卡主
[其他解释]
引用:
刚才试了一下,实在是太慢了,一次读一行,45k的文件要11秒,确实卡不住了,屏幕上文本在不停的滚动。


是啊。不断的滚动。我看了下QTextEdit源码,append数据后,他会将滚动条setValue到最后面。
还有个问题请教下。
我QMessageBox::about(this,"","");
我在MainWindow中设置了字体。为什么QMessageBox却不会继承这个字体呢?我将this传入了QMessageBox啊。

[其他解释]
刚才试了一下,实在是太慢了,一次读一行,45k的文件要11秒,确实卡不住了,屏幕上文本在不停的滚动。
[其他解释]
据我知道的,这个this是确定子窗口(QMessageBox)的位置用的,有this,QMessageBox出现在parent的中间,
没有传this,QMessageBox显示在屏幕的中间。

热点排行