非阻塞工作中断文件拷贝
Non-blocking worker - interrupt file copy
我正在处理非常大的文件,其大小超过数百GB。用户需要能够在磁盘之间移动这些文件,并且在没有默认文件管理器的受限系统上。用户可能会意识到他们犯了一个错误并取消操作,而且据我所知,用户将不得不等待当前的复制或重命名操作完成。这可能会让他们感到沮丧,因为他们可能会等待几分钟,只看到他们的许多GB的文件仍然被复制。对于Copy,我可以删除第二个文件,但是对于用于移动文件的rename,我必须反向重复操作才能撤消它,这是不可接受的。
是否有一些方法可以中断copy()和rename(),我在QFile的文档中没有看到,或者我需要把我自己的类放在一起来处理复制和重命名?
我不认为文件大小对重命名所需的时间有任何影响。
对于拷贝- Qt没有提供内建的东西,你必须自己实现它。这里的关键问题是,您必须找到某种方法来连续轮询副本取消。这意味着你不能为了处理事件而锁定主线程。
你是否需要一个额外的线程来保持主线程的响应,或者决定使用主线程——在这两种情况下,你都需要实现"碎片"复制——一次使用一个缓冲区一个块,直到文件被复制或复制被取消。您需要它来处理用户事件并跟踪复制进度。
我建议你实现一个QObject
派生的复制助手worker类,它跟踪文件名,总大小,缓冲区大小,进度并在取消时清理。然后,您可以选择在主线程中使用它还是在专用线程中使用它。
编辑:找到了,但你最好再检查一下,因为它是作为一个例子做的,还没有经过彻底的测试:
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。你也可以很容易地调整它来移动文件
我认为你要找的函数不存在。
你可以做的是,而不是使用copy()函数,创建一个新文件,并逐步读取(qint64 maxSize)到一个QByteArray从旧文件和写入(const QByteArray &byteArray)到新文件。这样你就可以自己控制流程,只需检查用户是否在每次读/写之间按了取消键。
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 文本文件中的单词链表
- CMake-按正确顺序将项目与C运行时对象文件链接
- 使用新行和不使用新行读取文件
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 挂起和取消挂起一个文件DLL
- 捕获标准输出以压缩并使用 CTRL-C 中断会给出损坏的 zip 文件
- 使用个人C++库编译代码时,与头文件一起使用时会中断
- 在不中断引用的情况下移动静态库的 *.pdb 文件 - LNK4099
- Visual Studio从文件中填充数组时中断
- 找不到WCHAR.H文件-Xcode 9.0中断QT创建者 - 旧修复程序不起作用
- 创建文件中断-ddebug标志在C 的makefile中
- C++:中断指向库"lib"文件
- 如何使用 C++ 中的 BIOS 中断监视 Windows 中的所有文件更改
- 逐行计算文件:EOF 重复最后一个数字(不能使用中断)
- XCode 不会中断 #include 的 CPP 文件
- 非阻塞工作中断文件拷贝
- C++系统文件位/stat.h 突然中断"error: field ‘st_atim’ has incomplete type"
- 选择忽略VS2005中特定文件的调试中断