QFile :: copy()的进度条?

时间:2014-03-22 07:21:07

标签: c++ qt copy progress-bar qfile

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

3 个答案:

答案 0 :(得分:3)

您无法使用静态QFile :: copy()方法执行此操作。

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

如果您需要在后台工作,则应使用QThread实现它。

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

你可以在这里查看相当广泛的Qt 4课程:http://docs.huihoo.com/qt/solutions/4/qtcopydialog/qtfilecopier.html但我不确定这是否会因其复杂性而有所帮助。

答案 1 :(得分:1)

这是一个显示的最小示例:

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();
}

答案 2 :(得分:-1)

查看QFile从[{3}}派生的课程,有一个信号bytesWritten()连接到该课程并通过QFileInfo(fromFile).size()统计文件大小以获取有关如何使用的信息信号检查我的其他QIODevice