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() 的实现与上传类似,就不粘贴了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值