QT - QFile拷贝操作极慢

QT - QFile copy operation extremely slow

本文关键字:操作 拷贝 QFile QT      更新时间:2023-10-16

我正在开发一个应用程序,需要将大量文件从一个文件夹复制到另一个文件夹,使用QT (5.6.1)

为此,我一直在使用QFile::copy()方法。这工作得很好,除了一件事:非常慢。与使用windows资源管理器进行相同的复制操作相比,花费的时间是前者的两倍以上。

想知道为什么会这样,我深入研究了QT源代码,我在qfile.cpp中发现了这一点,这看起来很相关:

char block[4096];
qint64 totalRead = 0;
while(!atEnd()) {
    qint64 in = read(block, sizeof(block));
    if (in <= 0)
        break;
    totalRead += in;
    if(in != out.write(block, in)) {
        close();
        d->setError(QFile::CopyError, tr("Failure to write block"));
        error = true;
        break;
    }
}

所以,据我所知,复制操作是使用一个4096字节的缓冲区。这对于复制操作来说是非常小的,并且很可能是问题的原因。我所做的就是将缓冲区的大小改为:

char block[4194304]; // 4MB buffer

然后我重新构建了整个QT库来包含这个更改。然而,所有的修改都完全破坏了这个方法。现在,当我的应用程序试图调用QFile::Copy()时,操作立即中断(方法甚至没有开始运行,根据QtCreator的调试器,在第一行之前停止)。调试器告诉我:

The inferior stopped because it received a signal from the Operating System.
Signal name :
SIGSEGV
Signal meaning :
Segmentation fault

我的c++有点生疏,但我不明白为什么仅仅改变数组的分配大小就可以完全破坏一个方法…谁能帮上忙?

1)告诉我为什么QFile:Copy()是如此缓慢(我错过了什么?它不仅在我的个人电脑上运行(在几台不同的机器上进行了测试)。而coulprit实际上是我上面发布的代码还是其他东西?2)告诉我为什么一个改变完全破坏了QFile

您的更改破坏QFile的原因是4M缓冲区无法容纳堆栈(默认的堆栈大小通常是1M之类的)。一个快速的修复方法是:

std::vector<char> vec(4*1024*1024);
char *block = &vec.front();

这个向量会在堆上分配一个大的缓冲区(当你完成后会负责释放),你只需要将block指向向量的前面。

我认为你对为什么拷贝速度慢的分析是正确的。

嗯,更改缓冲区大小没有好处,因为这显然只是在派生函数engine()->copy()失败的情况下的回退。我不知道这个函数是如何工作的,我也不想浪费时间修改核心QT引擎类来完成这个工作。

最后,因为我的项目只应该在Windows上运行,所以我最终使用了本地的Win32复制函数。所以我将调用替换为:

QFile::copy(src, dest);

:

CopyFileExW((LPCWSTR)src.utf16(), (LPCWSTR)dest.utf16(), 0, this, 0, 0);

请注意,必须使用#include "windows.h"才能使此调用工作。

这似乎不再是新版本的Qt(我使用5.9.2)的问题。请查看https://code.woboq.org/qt5/qtbase/src/corelib/io/qfilesystemengine_win.cpp.html中的QFileSystemEngine::copyFile(),代码使用本地函数CopyFile2。我的测试也证实了QFile::copy()与Windows上的本机实现相当。看来Qt在这方面已经取得了一些进展。