本文基于QT5.8使用QNetworkAccessManager类进行利用FTP协议的上传和下载操作,Qt4中使用的QFtp模块在QT5后被移除,如果有需要可以去GitHub上下载编译后使用(官方地址:https://github.com/qt/qtftp),使用QFtp和QUrlInfo可以实现获得服务器端的文件路径,结合TreeWidget实现目录预览。现在官方推荐使用的是QNetworkAccessManager类,在使用QNetworkAccessManager类之前,请先保证自己的QT版本为QT5.X。
我使用的服务器端是在Linux下配置的FTP服务器,客户端的QT代码是在Windows上编译运行的,FTP的服务器配置可以在我的另一篇博客中查看(https://blog.csdn.net/Sakuya__/article/details/86597994)。
本文代码下载:
CSDN下载
GitHub下载
百度云下载地址 提取码:wnnn
输入FTP服务器地址,用户名和密码,我的Linux服务器IP地址为192.168.43.129,用户名为sakuya,密码为abcd1234。
点击上传按钮选择文件上传
上传成功后
一、为了使用关于网络的类,首先,在Pro文件中加入一行
QT += network
二、头文件mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
bool initFTP();
void replyFinished(QNetworkReply*);
void loadProgress(qint64 bytesSent, qint64 bytesTotal);
QString getFileName(QString m_filePath);
void readContent();
void replyError(QNetworkReply::NetworkError error);
private slots:
void on_Btn_upload_clicked();
void on_Btn_download_clicked();
private:
Ui::MainWindow *ui;
QNetworkAccessManager *accessManager;
QString ftpPath;
QString user;
QString password;
QFile *file;
QNetworkReply *reply;
};
#endif // MAINWINDOW_H
三、mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 设置进度条
ui->progressBar->setValue(0);
ui->progressBar->setAlignment(Qt::AlignRight | Qt::AlignVCenter); // 对齐方式
ui->progressBar->setFormat(QString::fromUtf8("当前无任务:%1%").arg(QString::number(0, 'f', 1)));
}
MainWindow::~MainWindow()
{
delete ui;
}
// 初始化记录URL地址,用户名,密码,并检测URL地址的合法性
bool MainWindow::initFTP()
{
// 判断有没有填写URL地址和用户名、密码
if (ui->lineEdit_ftp->text().isEmpty()) {
QMessageBox::critical(NULL, tr("Error"), "URL地址不能为空");
return false;
}
else if (ui->lineEdit_user->text().isEmpty()) {
QMessageBox::critical(NULL, tr("Error"), "user不能为空");
return false;
}
else if (ui->lineEdit_user->text().isEmpty()) {
QMessageBox::critical(NULL, tr("Error"), "密码不能为空");
return false;
}
else {
ftpPath = ui->lineEdit_ftp->text();
user = ui->lineEdit_user->text();
password = ui->lineEdit_password->text();
// 检测URL地址是否合法
QUrl url = QUrl(ftpPath);
if (!url.isValid()) {
QMessageBox::critical(NULL, tr("Error"), "URL地址不合法!");
return false;
}
else if (url.scheme() != "ftp") {
QMessageBox::critical(NULL, tr("Error"), "URL地址必须以ftp开头!");
return false;
}
return true;
}
}
// 删除指针,更新和关闭文件
void MainWindow::replyFinished(QNetworkReply*)
{
if (reply->error() == QNetworkReply::NoError) {
reply->deleteLater();
file->flush();
file->close();
}
else {
QMessageBox::critical(NULL, tr("Error"), "错误!!!");
}
}
// 更新进度条
void MainWindow::loadProgress(qint64 bytesSent, qint64 bytesTotal)
{
ui->progressBar->setValue(0);
qDebug() << "loaded" << bytesSent << "of" << bytesTotal;
ui->progressBar->setMaximum(bytesTotal); //最大值
ui->progressBar->setValue(bytesSent); //当前值
double currentProgress = (bytesSent - ui->progressBar->minimum()) * 100.0 / (bytesTotal - ui->progressBar->minimum());
ui->progressBar->setFormat(QString::fromUtf8("当前进度为:%1%").arg(QString::number(currentProgress, 'f', 1)));
}
// 获得传入路径的文件名
QString MainWindow::getFileName(QString m_filePath)
{
QString temp;
QString fileName;
int count = -1;
fileName = m_filePath;
for(int i = 0; temp != "/"; i++)
{
temp = fileName.right(1);
fileName.chop(1);
count++;
}
fileName = m_filePath.right(count);
return fileName;
}
// 下载过程出错,进行报错处理(超时处理也是丢出超时信号,交由此槽函数进行处理)
void MainWindow::replyError(QNetworkReply::NetworkError error)
{
auto metaEnum = QMetaEnum::fromType();
// 枚举值转换为字符串
auto errStr = metaEnum.valueToKey(error);
QMessageBox::critical(NULL, tr("Error"), QString(errStr));
file->deleteLater();
file = Q_NULLPTR;
reply->deleteLater();
}
// 下载时向本地文件中写入数据
void MainWindow::readContent()
{
file->write(reply->readAll());
}
// 上传文件
void MainWindow::on_Btn_upload_clicked()
{
if (initFTP()) {
// 得到选择的文件的路径,保存在字符串链表中
QStringList string_list;
string_list = QFileDialog::getOpenFileNames(this, tr("选择文件"), "", tr("Files (*)"));
if (!string_list.isEmpty()) {
for (int i = 0; i < string_list.count(); i++) {
QString filePath;
filePath = string_list.at(i);
file = new QFile(filePath);
file->open(QIODevice::ReadOnly);
QByteArray byte_file = file->readAll();
QString fileName;
fileName = getFileName(filePath);
QString m_ftpPath;
m_ftpPath = ftpPath + "/" + fileName;
// 把选中的文件上传到服务器
accessManager = new QNetworkAccessManager(this);
accessManager->setNetworkAccessible(QNetworkAccessManager::Accessible);
QUrl url(m_ftpPath);
url.setPort(21);
url.setUserName(user);
url.setPassword(password);
QNetworkRequest request(url);
reply = accessManager->put(request, byte_file);
connect(accessManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
connect(reply, SIGNAL(uploadProgress(qint64 ,qint64)), this, SLOT(loadProgress(qint64 ,qint64)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),SLOT(replyError(QNetworkReply::NetworkError)));
}
}
}
}
// 下载文件
void MainWindow::on_Btn_download_clicked()
{
if (initFTP()) {
QString folderPath;
folderPath = QFileDialog::getExistingDirectory(this, tr("选择文件"), "", QFileDialog::ShowDirsOnly);
file = new QFile(folderPath + "/test.jpg");
file->open(QIODevice::WriteOnly);
// 从服务器上下载文件到选中文件夹
QNetworkAccessManager *accessManager = new QNetworkAccessManager(this);
accessManager->setNetworkAccessible(QNetworkAccessManager::Accessible);
QUrl url("ftp://192.168.43.129/software/timg.jpeg");
url.setPort(21);
url.setUserName("jinxiaodan");
url.setPassword("abcd1234");
QNetworkRequest request(url);
reply = accessManager->get(request);
connect((QObject *)reply, SIGNAL(readyRead()), this, SLOT(readContent()));
connect(accessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
connect(reply, SIGNAL(downloadProgress(qint64 ,qint64)), this, SLOT(loadProgress(qint64 ,qint64)));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),SLOT(replyError(QNetworkReply::NetworkError)));
}
}
以上则为全部代码,自己新建项目,把代码复制进去,按照开始展示的界面设置UI界面,把代码中的登录服务器地址、用户名和密码改为你自己的即可。
下载过程中文件写入是在主线程中进行的,如果文件过大,频繁写入会造成主线程卡顿现象。要避免此种情况,请在工作线程中进行。
另外,如果想要实现目录预览功能请使用QFtp和QUrlInfo,可以看到服务器端的文件目录,选择文件要下载的文件,QNetworkAccessManager只能更改源代码选择自己想要下载的文件。