非阻塞的工作人员 – 中断文件副本
我正在处理非常大的文件,超过几百GB的大小。 用户需要能够在磁盘之间移动这些文件,并且位于没有默认文件pipe理器的受限系统上。 用户可能意识到他们犯了错误并取消了操作,并且据我所知,用户将不得不等待当前的复制或重命名操作才能完成。 这可能让他们感到沮丧,因为他们等待几分钟,只能看到他们的许多GB文件仍然被复制。 在复制的情况下,我可以删除第二个文件,但在重命名的情况下,我正在使用移动文件,我不得不重复操作反向撤消它,这是根本不能接受的。
有没有办法打断我没有在QFile的文档中看到copy()和rename(),或者我需要把我自己的类放在一起来处理复制和重命名?
我不认为文件大小会影响重命名的时间。
对于副本 – Qt没有提供任何内置的,你必须自己实现它。 这里关键的一点是,你将不得不寻找一些方法来连续取消复制。 这意味着您无法locking主线程以便能够处理事件。
无论是为了保持主线程响应,还是决定使用主线程,都需要一个额外的线程 – 在这两种情况下,您都需要实现“分段”复制 – 一次一个块,使用一个缓冲区,直到文件复制或复制被取消。 您需要这样才能够处理用户事件并跟踪复制进度。
我build议你实现一个QObject
派生的副本助手工人类,跟踪文件名,总大小,缓冲区大小,进度和清理取消。 那么是否将在主线程或专用线程中使用它是一个select问题。
编辑:find它,但你最好仔细检查它,因为它是作为一个例子,并没有经过彻底的testing:
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()
复制助手/closures复制对话框或其他。 您可以启用经过的计时器,并使用它来实现经过时间的属性和估计的时间。 暂停是另一个可能实现的function。 使用QMetaObject::invokeMethod()
允许事件循环定期处理用户事件,因此您可以取消和更新从0到1的进度。您也可以轻松地调整它以移动文件。
我不认为你正在寻找的function存在。
你可以做的是不使用copy()函数,创build一个新文件,从旧文件逐步读取(qint64 maxSize)到一个QByteArray,并写入(const QByteArray&byteArray)到新文件。 这样您就可以自己控制stream量,只要检查用户是否在每次读取/写入之间都没有按下取消button。