Ответ 1
Я не думаю, что размер файла влияет на продолжительность переименования.
Для копии - Qt не предлагает ничего встроенного, вы должны реализовать его самостоятельно. Ключевым вопросом здесь является то, что вам нужно будет найти способ опроса для отмены копирования непрерывно. Это означает, что вы не можете заблокировать основной поток, чтобы иметь возможность обрабатывать события.
Если вы идете на дополнительный поток, чтобы поддерживать основной поток в ответ или решили использовать основной поток, в обоих случаях вам потребуется реализовать "фрагментированное" копирование - по одному фрагменту за раз, используя буфер, пока файл копируется или копирование отменяется. Это нужно, чтобы обрабатывать пользовательские события и отслеживать ход копирования.
Я предлагаю вам реализовать класс рабочего помощника QObject
, который отслеживает имя файла, общий размер, размер буфера, прогресс и очистку от отмены. Тогда вы можете выбрать, будете ли вы использовать его в основном потоке или в выделенном потоке.
EDIT: нашел его, но вам лучше проверить его, поскольку это было сделано в качестве примера и не было тщательно протестировано:
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. Вы можете легко настроить его и для перемещения файлов.