我使用QFile作为文件阅读器和文件编写器,从我的应用程序内部将文件复制到USB。我一直试图找出为什么我的文件复制到USB(带进度条)花了这么长时间。我终于发现,当我关闭用于写入的QFile对象时,close()操作可以在实际写入操作所花费的时间内完成。这些是非常大的文件,我读取/写入16384字节的块,然后我发送信号到GUI以增加用户查看的进度条。我最后在每次写入后添加了对flush()的调用,因为我认为这是因为out stream实际上还没有写入磁盘。这并没有什么不同。传出的QFile对象的关闭仍然需要比写入时间(复制前后的时间,以及每个QFile :: close()调用之前和之后的时间长得多,时间代码已被删除阅读方便,我也调试了,看到它发生了)。当然,不调用close()函数也没有用,因为QFile对象的破坏会导致它被调用。
我的代码如下(减去错误检查,目标空间检查等):
void FileCopy::run()
{
QByteArray bytes;
int totalBytesWritten = 0;
int inListSize = inList.size();
for (int i=0; !canceled && i<inListSize; i++)
{
QString inPath = inList.at(i).inPath;
QString outPath = inList.at(i).outPath;
QFile inFile(inPath);
QFile outFile(outPath);
int filesize = inFile.size();
int bytesWritten = 0;
if (!inFile.open(QIODevice::ReadOnly))
{
return;
}
if (!outFile.open(QIODevice::WriteOnly))
{
inFile.close();
return;
}
// copy the FCS file with progress
while (!canceled && bytesWritten < filesize)
{
bytes = inFile.read(MAXBYTES);
qint64 outsize = outFile.write(bytes);
outFile.flush();
if (outsize != bytes.size())
{
break;
}
bytesWritten += outsize;
totalBytesWritten += outsize;
Q_EMIT signalBytesCopied(totalBytesWritten, i+1, inListSize);
QThread::usleep(100); // allow time for detecting a cancel
}
inFile.close();
outFile.close();
}
// Other error checking done here
}
有人能看到通过这种方式吗?我实际上更喜欢进度条移动得更慢,更准确地向用户显示副本的状态,而不是让进度条在不到一半的时间内读取100%,并且接近实际完成。
我也尝试使用QSaveFile而不是QFile作为输出,但QSaveFile :: commit()具有相同的确切问题,需要更多时间来提交而不是完成实际的复制循环。我认为这是因为,在下面,它使用与QFile相同的功能,派生自QIoDevice。
我考虑过转向使用标准流,但我希望在此应用程序中如何保持文件处理的一致性。但是,如果QFile :: close()将需要这么长时间才能结束,这是一种可能性。或者标准流可能会出现同样的问题吗?
我正在使用Qt5.1.1和Qt 1.2.2 VS插件在VS7上安装Win7 32位盒子。感谢您的任何建议。
答案 0 :(得分:1)
在编写时,操作系统可能只是将写入缓存在内存中(快速)。但是当你关闭文件时,它必须将所有数据刷新到磁盘(速度很慢 - 特别是如果它还没有实际写入任何)。因此,关闭文件必须等待操作系统实际将所有数据放入磁盘(USB),并且那时可能实际上是所有数据。
操作系统之所以做这样的事情当然是为了加快写入速度 - 而且通常他们可以在没有其他任何事情发生时将数据刷新到磁盘上(所以你不要这样做)真的注意到实际成本,因为它随着时间的推移而摊销,没有其他任何事情发生)。但是,如果你只是写,然后马上关闭,你会注意到。 注意:替代方案是写入调用速度较慢 - 您仍然会花费相同的实际时间。