我认为文件大小对重命名需要多长时间没有任何影响。
对于副本 - Qt 没有提供任何内置功能,您必须自己实现它。这里的关键问题是您必须找到某种方法来不断地轮询副本取消。这意味着您不能锁定主线程以便能够处理事件。
无论您是使用额外线程来保持主线程响应,还是决定使用主线程 - 在这两种情况下,您都需要实现“碎片化”复制 - 使用缓冲区一次一个块,直到文件被复制或复制被取消。您需要它才能处理用户事件并跟踪复制进度。
我建议你实现一个QObject 派生的复制助手工作类,它跟踪文件名、总大小、缓冲区大小、进度和取消时的清理。那么是在主线程中使用还是在专用线程中使用是一个选择问题。
编辑:找到了,但您最好仔细检查一下,因为它是作为示例完成的,尚未经过彻底测试:
class CopyHelper : public QObject {
Q_OBJECT
Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged)
public:
CopyHelper(QString sPath, QString dPath, quint64 bSize = 1024 * 1024) :
isCancelled(false), bufferSize(bSize), prog(0.0), source(sPath), destination(dPath), position(0) { }
~CopyHelper() { free(buff); }
qreal progress() const { return prog; }
void setProgress(qreal p) {
if (p != prog) {
prog = p;
emit progressChanged();
}
}
public slots:
void begin() {
if (!source.open(QIODevice::ReadOnly)) {
qDebug() << "could not open source, aborting";
emit done();
return;
}
fileSize = source.size();
if (!destination.open(QIODevice::WriteOnly)) {
qDebug() << "could not open destination, aborting";
// maybe check for overwriting and ask to proceed
emit done();
return;
}
if (!destination.resize(fileSize)) {
qDebug() << "could not resize, aborting";
emit done();
return;
}
buff = (char*)malloc(bufferSize);
if (!buff) {
qDebug() << "could not allocate buffer, aborting";
emit done();
return;
}
QMetaObject::invokeMethod(this, "step", Qt::QueuedConnection);
//timer.start();
}
void step() {
if (!isCancelled) {
if (position < fileSize) {
quint64 chunk = fileSize - position;
quint64 l = chunk > bufferSize ? bufferSize : chunk;
source.read(buff, l);
destination.write(buff, l);
position += l;
source.seek(position);
destination.seek(position);
setProgress((qreal)position / fileSize);
//std::this_thread::sleep_for(std::chrono::milliseconds(100)); // for testing
QMetaObject::invokeMethod(this, "step", Qt::QueuedConnection);
} else {
//qDebug() << timer.elapsed();
emit done();
return;
}
} else {
if (!destination.remove()) qDebug() << "delete failed";
emit done();
}
}
void cancel() { isCancelled = true; }
signals:
void progressChanged();
void done();
private:
bool isCancelled;
quint64 bufferSize;
qreal prog;
QFile source, destination;
quint64 fileSize, position;
char * buff;
//QElapsedTimer timer;
};
done() 信号用于deleteLater() 复制助手/关闭复制对话框等。您可以启用经过计时器并使用它来实现经过时间属性和估计时间。暂停是另一个可能实现的功能。使用QMetaObject::invokeMethod() 允许事件循环定期处理用户事件,以便您可以取消和更新从 0 到 1 的进度。您也可以轻松地调整它以移动文件。