进度条带有QFile::copy()

Progress bar with QFile::copy()?

本文关键字:copy QFile      更新时间:2023-10-16

我正在制作一个在Qt中复制文件的程序,我想知道如何使用QProgressBarbool QFile::copy(const QString & fileName, const QString & newName)。这是可能的copy函数吗?复制过程可以暂停吗?

不能使用静态QFile::copy()方法。

正如Maciej之前所说,您需要编写自己的类。它应该使用两个QFile对象,一个用于读,一个用于写。按部分传输数据(例如,整个文件大小的1%),并在每个部分之后发出进度信号。您可以将此信号连接到进度对话框。

如果你需要它在后台工作,你应该使用QThread来实现它。

首先尝试决定是否需要一个类来异步地(不阻塞GUI)或同步地(阻塞GUI)执行复制工作。后者更容易编程,但大多数时候不是你想要的(例如,如果GUI被阻塞,你不能通过点击按钮来取消或暂停复制操作)。

您可以在这里查看一个相当广泛的Qt 4类:http://docs.huihoo.com/qt/solutions/4/qtcopydialog/qtfilecopier.html但我不确定这是否会有所帮助,因为它的复杂性。

这是一个最小的示例:

filecopyer.h:

/*
* This is a minimal example to show thread-based QFile copy operation with progress notfication.
* See here for QFile limitations: https://doc.qt.io/qt-5/qfile.html#platform-specific-issues
* Copyright (C) 2019 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _FILE_COPYER_H
#define _FILE_COPYER_H
#include <QtCore/qstring.h>
#include <QtCore/qobject.h>
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qvector.h>
#include <QtCore/qthread.h>
class FileCopyer : public QObject {
    Q_OBJECT
        Q_PROPERTY(qint64 chunksize READ chunkSize WRITE setChunkSize)
        Q_PROPERTY(QVector<QString> sourcePaths READ sourcePaths WRITE setSourcePaths)
        Q_PROPERTY(QVector<QString> destinationPaths READ destinationPaths WRITE setDestinationPaths)
public:
    static const int DEFAULT_CHUNK_SIZE = 1024 * 1024 * 1;
    FileCopyer(QThread*);
    ~FileCopyer();
    qint64 chunkSize() const {
        return _chunk;
    }
    void setChunkSize(qint64 ch) {
        _chunk = ch;
    }
    QVector<QString> sourcePaths() const {
        return src;
    }
    void setSourcePaths(const QVector<QString>& _src) {
        src = _src;
    }
    QVector<QString> destinationPaths() const {
        return dst;
    }
    void setDestinationPaths(const QVector<QString>& _dst) {
        dst = _dst;
    }
    protected slots:
    void copy();
private:
    QVector<QString> src, dst;
    qint64 _chunk;
signals:
    void copyProgress(qint64 bytesCopied, qint64 bytesTotal);
    void finished(bool success);
};
#endif // !_FILE_COPYER_H

filecopyer.cpp:

/*
* This is a minimal example to show thread-based QFile copy operation with progress notfication.
* See here for QFile limitations: https://doc.qt.io/qt-5/qfile.html#platform-specific-issues
* Copyright (C) 2019 Iman Ahmadvand
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* It is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <QtCore/qdebug.h>
#include "filecopyer.h"
FileCopyer::FileCopyer(QThread* _thread) :QObject(nullptr) {
    moveToThread(_thread);
    setChunkSize(DEFAULT_CHUNK_SIZE);
    QObject::connect(_thread, &QThread::started, this, &FileCopyer::copy);
    QObject::connect(this, &FileCopyer::finished, _thread, &QThread::quit);
    QObject::connect(this, &FileCopyer::finished, this, &FileCopyer::deleteLater);
    QObject::connect(_thread, &QThread::finished, _thread, &QThread::deleteLater);
}
FileCopyer::~FileCopyer() {
}
void FileCopyer::copy() {
    if (src.isEmpty() || dst.isEmpty()) {
        qWarning() << QStringLiteral("source or destination paths are empty!");
        emit finished(false);
        return;
    }
    if (src.count() != dst.count()) {
        qWarning() << QStringLiteral("source or destination paths doesn't match!");
        emit finished(false);
        return;
    }
    qint64 total = 0, written = 0;
    for (const auto& f : src)
        total += QFileInfo(f).size();
    qInfo() << QStringLiteral("%1 bytes should be write in total").arg(total);
    int indx = 0;
    qInfo() << QStringLiteral("writing with chunk size of %1 byte").arg(chunkSize());
    while (indx < src.count()) {
        const auto dstPath = dst.at(indx);
        QFile srcFile(src.at(indx));
        QFile dstFile(dstPath);
        if (QFile::exists(dstPath)) {
            qInfo() << QStringLiteral("file %1 alreasy exists, overwriting...").arg(dstPath);
            QFile::remove(dstPath);
        }
        if (!srcFile.open(QFileDevice::ReadOnly)) {
            qWarning() << QStringLiteral("failed to open %1 (error:%1)").arg(srcFile.errorString());
            indx++;
            continue; // skip
        }
        if (!dstFile.open(QFileDevice::WriteOnly)) {
            qWarning() << QStringLiteral("failed to open %1 (error:%1)").arg(dstFile.errorString());
            indx++;
            continue; // skip
        }
        /* copy the content in portion of chunk size */
        qint64 fSize = srcFile.size();
        while (fSize) {
            const auto data = srcFile.read(chunkSize());
            const auto _written = dstFile.write(data);
            if (data.size() == _written) {
                written += _written;
                fSize -= data.size();
                emit copyProgress(written, total);
            } else {
                qWarning() << QStringLiteral("failed to write to %1 (error:%2)").arg(dstFile.fileName()).arg(dstFile.errorString());
                fSize = 0;
                break; // skip this operation
            }
        }
        srcFile.close();
        dstFile.close();
        indx++;
    }
    if (total == written) {
        qInfo() << QStringLiteral("progress finished, %1 bytes of %2 has been written").arg(written).arg(total);
        emit finished(true);
    } else {
        emit finished(false);
    }
}

main.cpp:

#include <QtWidgets/QApplication>
#include "filecopyer.h"
int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    auto local = new QThread;
    auto worker = new FileCopyer(local);
    QObject::connect(worker, &FileCopyer::finished, [](bool s) {
        s ? qDebug() << "FINISHED" : qDebug() << "FAILED";
    });
    QObject::connect(worker, &FileCopyer::copyProgress, [](qint64 copy, qint64 total) {
        qDebug() << QStringLiteral("PROGRESS => %1").arg(qreal(copy) / qreal(total) * 100.0);
    });
    worker->setSourcePaths(/* src-paths */); // e.g: ~/content/example.mp4
    worker->setDestinationPaths(/* dst-paths */); // e.g /usr/local/example.mp4
    local->start();
    return a.exec();
}

检查QFile从QIODevice派生的类,有一个信号bytesWritten()连接到它并通过QFileInfo(fromFile).size()启动文件大小以获得读取如何使用信号检查我的其他答案