QT - QFile 复制操作极其缓慢
QT - QFile copy operation extremely slow
我正在开发一个需要将大量文件从一个文件夹复制到另一个文件夹的应用程序,使用 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() 这么慢(我错过了什么吗?它不仅在我的 PC 上,还在几台不同的机器上测试过)。罪魁祸首实际上是我在上面发布的代码还是完全是其他东西?
2) 告诉我为什么那个改变完全破坏了 QFile
您的更改破坏 QFile 的原因是 4M 的缓冲区不适合堆栈(默认堆栈大小通常约为 1M)。快速修复是:
std::vector<char> vec(4*1024*1024);
char *block = &vec.front();
vector 将在堆上分配大缓冲区(并在完成后负责释放),您只需将 block
指向 vector 的前面。
我认为您对复制速度慢的原因的分析很到位。
好吧,更改缓冲区大小没有任何好处,因为这显然只是派生函数 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 在这方面取得了一些进展。
我正在开发一个需要将大量文件从一个文件夹复制到另一个文件夹的应用程序,使用 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() 这么慢(我错过了什么吗?它不仅在我的 PC 上,还在几台不同的机器上测试过)。罪魁祸首实际上是我在上面发布的代码还是完全是其他东西? 2) 告诉我为什么那个改变完全破坏了 QFile
您的更改破坏 QFile 的原因是 4M 的缓冲区不适合堆栈(默认堆栈大小通常约为 1M)。快速修复是:
std::vector<char> vec(4*1024*1024);
char *block = &vec.front();
vector 将在堆上分配大缓冲区(并在完成后负责释放),您只需将 block
指向 vector 的前面。
我认为您对复制速度慢的原因的分析很到位。
好吧,更改缓冲区大小没有任何好处,因为这显然只是派生函数 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 在这方面取得了一些进展。