首页 > 后端开发 > C++ > 正文

如何中断 Qt 中的文件复制和重命名操作?

Susan Sarandon
发布: 2024-11-13 15:33:02
原创
994 人浏览过

How can I interrupt file copy and rename operations in Qt?

中断文件复制和重命名操作

在需要传输大文件并且用户需要能够取消操作的情况下, Qt 提供的默认 copy() 和 rename() 方法可能会受到限制。挑战在于如何在不引入显着性能开销或用户挫败感的情况下中断这些进程。

查询 Qt 中的中断支持

在研究 QFile 文档时,很明显 Qt不提供用于中断 copy() 或 rename() 操作的内置机制。因此,有必要考虑自定义实现策略来满足此要求。

复制中断的自定义实现

要创建非阻塞复制助手,一种选择是实现专用线程或利用主线程。无论哪种情况,都需要分段复制,即使用缓冲区以块的形式传输数据。通过使用缓冲区,可以跟踪操作进度并适应用户取消请求。

实现自定义复制助手的核心步骤可以描述如下:

  1. 创建一个 QObject 派生类来处理复制操作。
  2. 初始化源路径、目标路径、缓冲区大小、进度和取消时清理的属性。
  3. 定义一个 begin( ) 槽来启动复制过程,其中包括打开源文件和目标文件以及分配用于数据传输的缓冲区。
  4. 使用 QMetaObject::invokeMethod() 和 Qt:: 实现一个 step() 槽QueuedConnection,允许定期处理用户事件。在此槽中:

    • 检查复制是否未取消。
    • 使用源文件和目标文件以块的形式读写数据。
    • 根据位置与文件大小的比率。
    • 递归调用step()槽,直到整个文件被复制或取消。
  5. 定义一个cancel()槽以允许用户中断复制操作并在必要时删除目标文件。
  6. 利用信号通知感兴趣的各方有关进度更改和完成(done())。

示例实现

以下代码片段提供了复制帮助程序类的示例实现:

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;
};
登录后复制

结论

通过实现自定义副本helper 或使用提供的示例,可以创建可以被用户中断的非阻塞文件复制操作。这种方法可以实现响应灵敏且用户友好的文件传输,解决因无法取消的冗长操作而造成的挫败感。

以上是如何中断 Qt 中的文件复制和重命名操作?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板