【问题标题】:Qt: How can I copy a big data using QT?Qt:如何使用 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运行良好。

【问题讨论】:

  • 我在Qt 中使用的文件是您提到的大小的 10 倍。话虽如此,这是来自本地磁盘。过去,我在 Windows 客户端上通过 samba 网络共享读取类似大小的文件(几百 MB)时遇到问题。在那种情况下,我不得不将阅读分成更小的块。
  • 不要使用readAll()。对于那些懒得思考如何将输入作为流处理的程序员来说,这只是一个快速的技巧。如果您真的非常需要随机访问整个文件,请考虑对其进行内存映射(如果原生 mmap() 便携性不足,您可以使用 boost::interprocess)。
  • @JesperJuhl Buddy,我已经编辑了我的帖子。现在可以了吗?
  • 您应该在 read() 调用中使用不同的缓冲区大小进行基准测试,以找出最佳性能的缓冲区。

标签: c++ qt


【解决方案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 放入堆栈,您可能会用完内存/地址空间 - 导致您的程序崩溃。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      相关资源
      最近更新 更多