目录
第一种写法
.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);
}
}
中文文件依然会乱码