我不認爲文件大小對重命名需要多長時間有任何影響。
對於副本 - 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的進度。您也可以輕鬆調整它以移動文件。
我很害怕這個。只是幾個小時我寧願花在其他地方。我會按照你所建議的模式做一些事情,並且必須在另一個線程中確保GUI可以隨着進度而更新。光明的一面,我可以通過這種方式提供具體的文件。 – MildWolfie
至於重命名(),我用它來移動文件。當移動到同一磁盤上的另一個目錄時,它將保持不變,但從一個磁盤到另一個磁盤需要花費時間,具體取決於文件大小。 – MildWolfie
@MildWolfie - 我想我已經做了這樣的事情,會在幾個小時後檢查我什麼時候回家。 – dtech