Qt:QNetworkAccessManager使用ftp协议上传文件

目录

第一种写法

第二种


第一种写法

.h

#pragma once

#include <QMainWindow>
#include <QNetworkAccessManager>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    void Init();

    void Upload();
private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

private:
    Ui::MainWindow *ui;

    QStringList files;

    QNetworkAccessManager * manager = nullptr;
};

.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"

#include <QNetworkReply>
#include <QNetworkRequest>
#include <QFileDialog>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    Init();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::Init()
{
    manager = new QNetworkAccessManager(this);

    ui->progressBar->setMaximum(100);
}

void MainWindow::Upload()
{
    foreach (QString filepath, files)
    {
        QUrl remoteUrl("ftp://127.0.0.1:2122/" + QFileInfo(filepath).fileName());
        QNetworkRequest request(remoteUrl);
        request.setMaximumRedirectsAllowed(120000); // timeout in milliseconds
        request.setHeader(QNetworkRequest::ContentLengthHeader, QFile(filepath).size());
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");

        QFile file(filepath);
        file.open(QIODevice::ReadOnly);
        QByteArray data = file.readAll();       
        file.close();

        QNetworkReply* reply = manager->put(request, data);

        connect(reply, &QNetworkReply::uploadProgress, [=](qint64 bytesSent, qint64 bytesTotal) {
            qDebug() << "已上传:" << bytesSent << "字节,总共上传字节:"  << bytesTotal;
           
        });
        connect(reply, &QNetworkReply::finished, [=]() {
            if(reply->error() != QNetworkReply::NoError) {
                //error handling
            }
            reply->deleteLater();
        });
    }
}

void MainWindow::on_pushButton_clicked()
{
    files = QFileDialog::getOpenFileNames(this, "选择上传文件", QDir::homePath(), "Files (*.*)");

    foreach(QString file, files)
    {
        ui->textEdit->append(file);
    }
}

void MainWindow::on_pushButton_2_clicked()
{
    Upload();
}

void MainWindow::on_pushButton_3_clicked()
{
    ui->textEdit->clear();
}

界面:

存在问题:中文命名的文件名称会乱码

第二种

FtpManager.h

#pragma once

#include <QObject>

#include <QUrl>
#include <QFileInfo>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QTimer>
#include <QDebug>

#define DECLARE_INSTANCE_CLASS(className) \
private: \
    class GC \
    { \
    public: \
        ~GC() \
        { \
            delete className::Instance(); \
        } \
    }; \
    static className * _bll; \
public: \
    static className * Instance() \
    { \
        static GC _gc; \
        if (!_bll) \
            _bll = new className(); \
        return _bll; \
    }

#define REALIZE_INSTANCE_CLASS(className) \
    className * className::_bll = nullptr;



class FtpManager : public QObject
{
    Q_OBJECT
    DECLARE_INSTANCE_CLASS(FtpManager);
public:
    explicit FtpManager(QObject * parent = nullptr);

    // 设置地址和端口
    void SetHostPort(const QString &host, int port = 21);
    // 设置登录 FTP 服务器的用户名和密码
    void SetUserInfo(const QString &userName, const QString &password);

    // 上传文件 同步/阻塞模式 不会发送信号
    QNetworkReply::NetworkError UploadSync(const QString & srcFilePathName, const QString & ftpFilePathName, int timeoutMSec);
    QNetworkReply::NetworkError UploadSync(const QByteArray & srcData, const QString & ftpFilePathName, int timeoutMSec);
    // 下载文件 同步/阻塞模式 不会发送信号
    QNetworkReply::NetworkError DownloadSync(const QString & ftpFilePathName, const QString & srcFilePathName, int timeoutMSec);
    QNetworkReply::NetworkError DownloadSync(const QString & ftpFilePathName, QByteArray & srcData, int timeoutMSec);

    // 上传文件 异步 会发送 UploadProgress UploadFinished Error 信号
    QNetworkReply * UploadAsync(const QString & srcFilePathName, const QString & ftpFilePathName);
    QNetworkReply * UploadAsync(const QByteArray & srcData, const QString & ftpFilePathName);
    QNetworkReply * UploadBigFileAsync(QIODevice * srcData, const QString & ftpFilePathName);
    // 下载文件 异步 会发送 DownloadProgress DownloadFinished Error 信号
    QNetworkReply * DownloadAsync(const QString & ftpFilePathName, const QString & srcFilePathName);

signals:
    void Error(QNetworkReply::NetworkError);
    // 上传进度
    void UploadProgress(qint64 bytesSent, qint64 bytesTotal);
    // 下载进度
    void DownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
    // 完成,并会delete相关的QNetworkReply
    void UploadFinished();
    // 完成,并会delete相关的QNetworkReply
    void DownloadFinished();

private slots:
    void OnUploadFinished();
    // 下载过程中写文件
    void OnDownloadFinished();

private:
    QTimer * StartSingleShotTimer(QTimer * timer, int msec);

private:
    QUrl _FtpUrl;
    QFile _FileDownload;
    QNetworkAccessManager _NetworkManager;

};

.cpp

#include "FtpManager.h"

#include <QEventLoop>

REALIZE_INSTANCE_CLASS(FtpManager);
FtpManager::FtpManager(QObject * parent) : QObject(parent)
{
    // 设置协议
    _FtpUrl.setScheme("ftp");
}

void FtpManager::SetHostPort(const QString &host, int port)
{
    _FtpUrl.setHost(host);
    _FtpUrl.setPort(port);
}

void FtpManager::SetUserInfo(const QString &userName, const QString &password)
{
    _FtpUrl.setUserName(userName);
    _FtpUrl.setPassword(password);
}

QNetworkReply::NetworkError FtpManager::UploadSync(const QString & srcFilePathName, const QString & ftpFilePathName, int timeoutMSec)
{
    QFile file(srcFilePathName);
    file.open(QIODevice::ReadOnly);
    QByteArray data = file.readAll();
    file.close();

    return UploadSync(data, ftpFilePathName, timeoutMSec);
}

QNetworkReply::NetworkError FtpManager::UploadSync(const QByteArray & srcData, const QString & ftpFilePathName, int timeoutMSec)
{
    _FtpUrl.setPath(ftpFilePathName);

    QNetworkReply * pReply = _NetworkManager.put(QNetworkRequest(_FtpUrl), srcData);
    QTimer * timer = StartSingleShotTimer(new QTimer(this), timeoutMSec);

    QEventLoop eventLoop;
    connect(timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
    connect(pReply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);

    auto err = pReply->error();
    if (timer->remainingTime() == -1)
        err = QNetworkReply::TimeoutError;

    delete timer;
    pReply->abort();
    pReply->deleteLater();

    return err;
}

QNetworkReply::NetworkError FtpManager::DownloadSync(const QString & ftpFilePathName, const QString & srcFilePathName, int timeoutMSec)
{
    QByteArray array;
    QNetworkReply::NetworkError err = DownloadSync(ftpFilePathName, array, timeoutMSec);
    if (err == QNetworkReply::NoError)
    {
        QFile fileDownload(srcFilePathName);
        fileDownload.open(QIODevice::WriteOnly);
        fileDownload.write(array);
        fileDownload.close();
    }

    return err;
}

QNetworkReply::NetworkError FtpManager::DownloadSync(const QString & ftpFilePathName, QByteArray & srcData, int timeoutMSec)
{
    _FtpUrl.setPath(ftpFilePathName);

    QNetworkReply * pReply = _NetworkManager.get(QNetworkRequest(_FtpUrl));
    QTimer * timer = StartSingleShotTimer(new QTimer(this), timeoutMSec);

    QEventLoop eventLoop;
    connect(timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
    connect(pReply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);

    QNetworkReply::NetworkError err;
    if (timer->remainingTime() == -1)
    {
        err = QNetworkReply::TimeoutError;
    }
    else
    {
        err = pReply->error();
        if (err == QNetworkReply::NoError)
        {
            srcData = pReply->readAll();
        }
    }

    delete timer;
    pReply->abort();
    pReply->deleteLater();

    return err;
}

QNetworkReply * FtpManager::UploadAsync(const QString & srcFilePathName, const QString & ftpFilePathName)
{
//    QTime time;
//    time.start();
//    QFile file(srcFilePathName);

//    file.open(QIODevice::ReadOnly);
//    QByteArray data = file.readAll();
//    file.close();
//    int t1 = time.elapsed();
//    qDebug() <<"t1 = " << t1;


    //超过1G的大文件

    QFile * fileData = new QFile(srcFilePathName, this);

    if(fileData->open(QIODevice::ReadOnly))
    {

        qDebug() << "大文件";
        return UploadBigFileAsync(fileData, ftpFilePathName);
    }
    else
    {
        qDebug() << "open error";
//        return UploadAsync(data, ftpFilePathName);
    }
}

QNetworkReply *FtpManager::UploadAsync(const QByteArray &srcData, const QString &ftpFilePathName)
{
    _FtpUrl.setPath(ftpFilePathName);
    QNetworkReply * pReply = _NetworkManager.put(QNetworkRequest(_FtpUrl), srcData);

    connect(pReply, &QNetworkReply::finished, this, &FtpManager::OnUploadFinished);
    connect(pReply, &QNetworkReply::uploadProgress, this, &FtpManager::UploadProgress);
    connect(pReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
            this, &FtpManager::Error);

    return pReply;
}

QNetworkReply * FtpManager::UploadBigFileAsync(QIODevice *srcData, const QString & ftpFilePathName)
{
    _FtpUrl.setPath(ftpFilePathName);
    QNetworkReply * pReply = _NetworkManager.put(QNetworkRequest(_FtpUrl), srcData);

    connect(pReply, &QNetworkReply::finished, this, &FtpManager::OnUploadFinished);
    connect(pReply, &QNetworkReply::uploadProgress, this, &FtpManager::UploadProgress);
    connect(pReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
            this, &FtpManager::Error);

    return pReply;
}

QNetworkReply * FtpManager::DownloadAsync(const QString & ftpFilePathName, const QString & srcFilePathName)
{
    _FileDownload.setFileName(srcFilePathName);
    _FileDownload.open(QIODevice::WriteOnly);
    _FtpUrl.setPath(ftpFilePathName);

    QNetworkReply * pReply = _NetworkManager.get(QNetworkRequest(_FtpUrl));

    connect(pReply, &QNetworkReply::finished, this, &FtpManager::OnDownloadFinished);
    connect(pReply, &QNetworkReply::downloadProgress, this, &FtpManager::DownloadProgress);
    connect(pReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
            this, &FtpManager::Error);

    return pReply;
}

void FtpManager::OnUploadFinished()
{
    QNetworkReply * pReply = qobject_cast<QNetworkReply *>(sender());
    pReply->deleteLater();
    pReply = nullptr;

    emit UploadFinished();
}

void FtpManager::OnDownloadFinished()
{
    QNetworkReply * pReply = qobject_cast<QNetworkReply *>(sender());
    switch (pReply->error())
    {
    case QNetworkReply::NoError:
        {
            _FileDownload.write(pReply->readAll());
            _FileDownload.flush();
        }
        break;
    default:
        break;
    }

    _FileDownload.close();
    pReply->deleteLater();
    pReply = nullptr;

    emit DownloadFinished();
}

QTimer * FtpManager::StartSingleShotTimer(QTimer * timer, int msec)
{
    timer->start(msec);
    timer->setSingleShot(true);
    return timer;
}

使用

MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"

#include <QFileInfo>
#include <QDebug>
#include <QFileDialog>

#include "FtpManager.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->progressBar->setValue(0);

    QString ip = ui->lineEditIP->text().trimmed();
    int port = ui->spinBoxPort->value();
    QString userName = ui->lineEditUserName->text().trimmed();
    QString pwd = ui->lineEditPwd->text().trimmed();

    connect(&ftpManager, &FtpManager::UploadProgress, this, &MainWindow::SetProgressValue);
    connect(&ftpManager, &FtpManager::UploadFinished, this, []()
    {
        qDebug() << "文件上传完毕";
    });
    connect(&ftpManager, &FtpManager::Error, this, [](QNetworkReply::NetworkError err)
    {
        qDebug() << "出错: " << err;
    });

    ftpManager.SetHostPort(ip, port);
    ftpManager.SetUserInfo(userName, "");

    //test
    connect(FtpManager::Instance(), &FtpManager::UploadProgress, this, &MainWindow::SetProgressValue);
    connect(FtpManager::Instance(), &FtpManager::UploadFinished, this, &MainWindow::OnUploadFinished);
    connect(FtpManager::Instance(), &FtpManager::Error, this, [](QNetworkReply::NetworkError err)
    {
        qDebug() << "出错: " << err;
    });

    FtpManager::Instance()->SetHostPort(ip, port);
    FtpManager::Instance()->SetUserInfo(userName, "");

}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_pushButton_clicked()
{     
    QString fileName = QFileInfo(ui->lineEditFilePath->text().trimmed()).fileName();

    QString ftpFileName = "/TestNewFtp/" + fileName;

    qDebug() << "ftpFileName:" << ftpFileName;
    qDebug() << "localFileName: " << ui->lineEditFilePath->text().trimmed();


   
    time.start();
    auto err = FtpManager::Instance()->UploadAsync(ui->lineEditFilePath->text().trimmed(), ftpFileName);

}

void MainWindow::SetProgressValue(qint64 bytesSent, qint64 bytesTotal)
{
    qDebug() << "已上传:" << bytesSent << "总字节: " << bytesTotal << "进度:" << 100 * (bytesSent / (double)bytesTotal);
    ui->progressBar->setValue(100 * (bytesSent/ (double)bytesTotal));
}

void MainWindow::OnUploadFinished()
{
    qDebug() << "上传完毕,用时: " << time.elapsed();
}

void MainWindow::on_pushButton_2_clicked()
{
    QString path = QFileDialog::getExistingDirectory(this, tr("选择目录"),
                                                     "./",
                                                     QFileDialog::ShowDirsOnly
                                                     | QFileDialog::DontResolveSymlinks);
    if(!path.isEmpty())
    {
        ui->lineEditFtpFolder->setText(path);
    }
}

void MainWindow::on_pushButton_3_clicked()
{
    QString path = QFileDialog::getOpenFileName(this, tr("选择文件"), "./" );
    if(!path.isEmpty())
    {
        ui->lineEditFilePath->setText(path);
    }
}

中文文件依然会乱码

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值