Qt:如何使用 QT 复制大数据?
Posted
技术标签:
【中文标题】Qt:如何使用 QT 复制大数据?【英文标题】:Qt: How can I copy a big data using QT? 【发布时间】:2018-04-05 12:47:30 【问题描述】:我想读取一个大数据,然后使用 Qt 将其写入一个新文件。
我试图读取一个大文件。而且大文件只有一行。我使用readAll()
和readLine()
进行测试。
如果数据文件600MB左右,我的代码虽然慢,但可以运行。
如果数据文件大约6GB,我的代码会失败。
你能给我一些建议吗?
更新 我的测试代码如下:
#include <QApplication>
#include <QFile>
#include <QTextStream>
#include <QTime>
#include <QDebug>
#define qcout qDebug()
void testFile07()
QFile inFile("../03_testFile/file/bigdata03.txt");
if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text))
qcout << inFile.errorString();
return ;
QFile outFile("../bigdata-read-02.txt");
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
return;
QTime time1, time2;
time1 = QTime::currentTime();
while(!inFile.atEnd())
QByteArray arr = inFile.read(3*1024);
outFile.write(arr);
time2 = QTime::currentTime();
qcout << time1.msecsTo(time2);
void testFile08()
QFile inFile("../03_testFile/file/bigdata03.txt");
if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QFile outFile("../bigdata-readall-02.txt");
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
return;
QTime time1, time2, time3;
time1 = QTime::currentTime();
QByteArray arr = inFile.readAll();
qcout << arr.size();
time3 = QTime::currentTime();
outFile.write(inFile.readAll());
time2 = QTime::currentTime();
qcout << time1.msecsTo(time2);
int main(int argc, char *argv[])
testFile07();
testFile08();
return 0;
测试后,我分享一下我的经验。
read()
和 readAll()
似乎都一样快;更确切地说,read()
稍微快一些。
真正的区别在于写作。
文件大小为600MB:
使用read
函数,读写文件耗时2.1s,读取875ms
使用readAll
函数,读写文件耗时10s,读取907ms
文件大小为6GB:
使用read
函数,读写文件耗时162s,读取58s
使用readAll
函数,得到错误答案0。Fail运行良好。
【问题讨论】:
请发minimal reproducible example。 我在Qt
中使用的文件是您提到的大小的 10 倍。话虽如此,这是来自本地磁盘。过去,我在 Windows 客户端上通过 samba 网络共享读取类似大小的文件(几百 MB)时遇到问题。在那种情况下,我不得不将阅读分成更小的块。
不要使用readAll()
。对于那些懒得思考如何将输入作为流处理的程序员来说,这只是一个快速的技巧。如果您真的非常需要随机访问整个文件,请考虑对其进行内存映射(如果原生 mmap()
便携性不足,您可以使用 boost::interprocess
)。
@JesperJuhl Buddy,我已经编辑了我的帖子。现在可以了吗?
您应该在 read() 调用中使用不同的缓冲区大小进行基准测试,以找出最佳性能的缓冲区。
【参考方案1】:
将这两个文件作为 QFiles 打开。在一个循环中,read 一个固定数量的字节,比如 4K,从输入文件到一个数组,然后write 那个数组到输出文件。继续,直到用完字节。
但是,如果您只想逐字复制文件,可以使用QFile::copy
【讨论】:
【参考方案2】:您可以使用QFile::map
并使用指向映射内存的指针一次性写入目标文件:
void copymappedfile(QString in_filename, QString out_filename)
QFile in_file(in_filename);
if(in_file.open(QFile::ReadOnly))
QFile out_file(out_filename);
if(out_file.open(QFile::WriteOnly))
const qint64 filesize = in_file.size();
uchar * mem = in_file.map(0, filesize, QFileDevice::MapPrivateOption);
out_file.write(reinterpret_cast<const char *>(mem) , filesize);
in_file.unmap(mem);
out_file.close();
in_file.close();
【讨论】:
我已经测试了你的代码。当文件大小为600MB时,复制文件只需1.6s左右。伟大的!当文件大小为6GB时,代码失败。【参考方案3】:要记住的一点:
使用read()
,您可以为当前读取的块指定最大大小(在您的示例中为 3*1024 字节),使用readAll()
,您告诉程序一次读取整个文件。
在第一种情况下,您(反复)将 3072 字节放入堆栈,写入它们,一旦当前循环迭代结束,它们就会从堆栈中删除。在第二种情况下,您将整个文件压入堆栈。一次向堆栈推送 600MB 可能是导致性能问题的原因。如果您尝试一次将 6GB 放入堆栈,您可能会用完内存/地址空间 - 导致您的程序崩溃。
【讨论】:
以上是关于Qt:如何使用 QT 复制大数据?的主要内容,如果未能解决你的问题,请参考以下文章