qt 实现 ftp 上传与下载

        最近接个需求,需要实现 ftp 的上传与下载,开始也是参考网上的一些写法,大概如下:

// 创建网络访问管理器
QNetworkAccessManager manager;

// 创建网络请求对象
QNetworkRequest request(QUrl(ftpUrl));

// 设置 FTP 用户名和密码
request.setRawHeader("Authorization", "Basic " + QByteArray("username:password").toBase64());

// 发送 PUT 请求,将文件上传到 FTP 服务器
QNetworkReply *reply = manager.put(request, &file);

        虽然 reply->error() 返回的是 QNetworkReply::NoError,但传输文件就是失败,而 reply->errorString() 返回的也只是 unknown error,无从下手。

        在此基础上尝试了多种方法,包括设置代理、设置被动模式等,均无效。后来只好尝试 QFtp 类,尽管这个类已被 qt5.0 版本废弃。

        一开始实现的基本这样:

ftp.connectToHost(host);
ftp.login(user, password);
ftp.put(&file, remoteFileName);
file.close();

        依然会报错,经一番研究后才发现每个 QFtp 类的每个接口都是异步的,在调用各方法时不能按顺序依次调用,需要有信号机制,这点从诸多方法的注释中也能了解:

The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished().

When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted.

        所以可以利用 qt 的信号机制来实现这点:

connect(&ftp, SIGNAL(commandFinished(int, bool)), this, SLOT(uploadHandleFinish(int, bool)));

        其中 uploadHandleFinish() 是根据业务需要自定义的方法:

void Class::uploadHandleFinish(int id, bool error)
{
    qDebug() << "id:" << id << ", error:" << error << ", msg:" << ftp.errorString();
    switch (id) {
        case 1:
            qDebug() << "ftp is connected to " << host;
            signal_id = ftp.login(USER_NAME, PASSWORD);
            break;
        case 2:
            qDebug() << "ftp is logined to " << host;
            signal_id = ftp.put(file, remote_path);
            break;
        case 3:
            qDebug() << "end upload to remote host" << host;
            upload_download = 0;
            if (file->isOpen()) {
                file->close();
                delete file;
            }
            ftp.disconnect();
            ftp.close();
            break;
        default:
            break;
    }
}

        当 connectToHost() 方法执行结束时会返回唯一标识1,信号器 handleFinish 收到1后可调用 login() 方法进行登录;

        待 login() 方法执行结束后返回唯一标识2,信号器 handleFinish 收到2后可调用 put() 方法进行上传,以此类推。

        这样就实现了 ftp 的上传功能,如果想看实时进度,可以绑定信号器 dataTransferProgress

connect(&ftp, SIGNAL(dataTransferProgress(qint64, qint64)), this, SLOT(ftpProgress(qint64, qint64)));

        ftpProgress() 也是自定义的方法,可实现如下:

int progress = 0;
void Class::ftpProgress(qint64 read_bytes, qint64 total_bytes)
{
    int percent = (int)((qreal) read_bytes / total_bytes * 100);
    if (percent < progress + 10) {
        return;
    }
    progress = percent;
    qDebug() << "upload to remote host" << host << "progress:" << progress << "%";
}

        这是并没有直接输出进度,而是做了些简单的处理。如果直接输出,那么该函数打印的会非常频繁,一秒钟就会触发多次,这里是设置了只当进度达到 10% 的整数倍时才记录。

        其实我一开始想的是设置信号器触发的频率,从源头解决,减少不必要的调用,但是搜了一圈,也没看到好的办法,只好在达到规定的进度时才打印出来,但实际上每次都还是有调用的。哪位小伙伴这块有更好的办法还请赐教哈!

        下载和上传差不多,主方法如下:

signal_id = ftp.connectToHost(host, FTP_PORT);

connect(&ftp, SIGNAL(commandFinished(int, bool)), this, SLOT(downloadHandleFinish(int,bool)));
connect(&ftp, SIGNAL(dataTransferProgress(qint64, qint64)), this, SLOT(ftpProgress(qint64, qint64)));

        自定义的 downloadHandleFinish()ftpProgress() 的实现与上传类似,就不粘贴了。

相关推荐

  1. qt 实现 ftp 下载

    2023-12-21 17:12:03       35 阅读
  2. FTP文件的下载

    2023-12-21 17:12:03       20 阅读
  3. C++进行FTP下载

    2023-12-21 17:12:03       35 阅读
  4. C#使用ftp进行文件下载功能

    2023-12-21 17:12:03       11 阅读
  5. axios 实现下载

    2023-12-21 17:12:03       13 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-21 17:12:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-21 17:12:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-21 17:12:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-21 17:12:03       20 阅读

热门阅读

  1. facebook广告投放有哪些需要注意的

    2023-12-21 17:12:03       35 阅读
  2. 在 Docker 上部署 Nacos 并连接到 MySQL

    2023-12-21 17:12:03       30 阅读
  3. 数据分析的基本步骤有哪些?

    2023-12-21 17:12:03       33 阅读
  4. 【密码学引论】密码协议

    2023-12-21 17:12:03       30 阅读
  5. 在Idea中创建基于工件的本地服务

    2023-12-21 17:12:03       43 阅读
  6. Codeforces Round 916 (Div. 3)(A~E2)

    2023-12-21 17:12:03       37 阅读
  7. 深度学习嵌入头embedding head解释

    2023-12-21 17:12:03       39 阅读
  8. 7-1 冰雹猜想

    2023-12-21 17:12:03       43 阅读
  9. minio 整合springboot

    2023-12-21 17:12:03       30 阅读
  10. Springboot Async 引起的循环依赖

    2023-12-21 17:12:03       37 阅读