我正在开发一个应用程序,需要使用 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()是如此之慢(我错过了什么?它不只是在我的电脑上,在几台不同的机器上测试过)。实际上是我上面发布的代码还是完全不同的代码? 2)告诉我为什么一个改变完全破坏了QFile
答案 0 :(得分:5)
您的更改破坏QFile的原因是4M缓冲区不适合堆栈(默认堆栈大小通常类似于1M)。快速解决方法是:
std::vector<char> vec(4*1024*1024);
char *block = &vec.front();
向量将在堆上分配大缓冲区(并在完成后负责解除分配),并且只需将block
指向向量的前面。
我认为您对复制速度缓慢的原因分析是正确的。
答案 1 :(得分:2)
好吧,改变缓冲区大小没有任何好处,因为在派生函数engine()->copy()
失败的情况下,这显然只是一个后备。我不确切知道该功能是如何工作的,我也不想浪费时间修改核心QT引擎类来使其工作。
最后,由于我的项目只能在Windows上运行,所以我最终使用了原生的Win32复制功能。所以我把我的电话换成了:
QFile::copy(src, dest);
使用:
CopyFileExW((LPCWSTR)src.utf16(), (LPCWSTR)dest.utf16(), 0, this, 0, 0);
请注意,此调用必须#include "windows.h"
才能生效。
答案 2 :(得分:2)
对于较新版本的Qt,我似乎不再是一个问题(我使用的是5.9.2)。请查看https://code.woboq.org/qt5/qtbase/src/corelib/io/qfilesystemengine_win.cpp.html中的QFileSystemEngine::copyFile()
代码使用原生函数CopyFile2
。此外,我的测试证实QFile::copy()
与Windows上的本机实现相同。似乎Qt在这方面取得了一些进展。