从Qt5开始,官方推荐使用QNetworkAccessManager进行Ftp和http的上传和下载操作;Qt4中使用的QtFtp模块即作为独立模块,需要自己从github上进行下载编译后使用(官方地址:https://github.com/qt/qtftp)。

官方的QtFtp最后一次更新为2014年,根据搜索的资料,其尚存在若干bug。不过有人对此代码在Github上进行维护和更新,如果需要使用的话,可以搜索一下。

QNetworkAccessManager的相关API比较丰富,但是相应也比较低级。如果需要对Ftp进行较为复杂的操作,在缺少资料的基础上就会很麻烦,需要较好的功底。

因为个人对Ftp的操作仅限于下载或者上传,因此使用`QNetworkAccessManager`即可满足要求。此处仅对下载进行示范,上传基本一致。

 #ifndef FTPGETWINDOW_H
#define FTPGETWINDOW_H #include <QWidget>
#include <QUrl>
#include <QDir>
#include <QNetworkReply> class QFile;
class QLabel;
class QLineEdit;
class QTextEdit;
class QPushButton;
class QProgressBar;
class QGridLayout; class QTimer;
class QNetworkAccessManager; class FtpgetWindow : public QWidget
{
Q_OBJECT public:
FtpgetWindow(QWidget *parent = );
~FtpgetWindow(); private slots:
void timeOut();
void updateSelectSaveDir();
void updateTaskRunningState();
void slotReadyRead();
void readReplyError(QNetworkReply::NetworkError error);
void downloadFinishReply(QNetworkReply* reply);
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); private:
bool checkUrl();
bool checkSaveDir();
bool createDownloadFile();
void startDownloadFile(); private:
qint64 fileDownloadSize;
qint64 lastDownloadSize;
QUrl url;
QDir saveDir;
QFile *file;
QTimer *timer;
QNetworkReply *downloadReply;
QNetworkAccessManager *downloadManager; QLabel *urlLabel;
QLabel *dirLoactionLabel;
QLabel *downlaodInfoLabel;
QLabel *runningTipLabel;
QLineEdit *urlTextEdit;
QLineEdit *dirTextEdit;
QTextEdit *downloadInfoTextEdit;
QPushButton *runningTaskButton;
QPushButton *dirLocationButton;
QProgressBar *progressBar;
QGridLayout *mainLayout;
}; #endif // FTPGETWINDOW_H

头文件无需赘述。

 #include "ftpgetwindow.h"

 #include <QLabel>
#include <QLineEdit>
#include <QTextEdit>
#include <QPushButton>
#include <QProgressBar>
#include <QGridLayout>
#include <QFileDialog> #include <QUrl>
#include <QDir>
#include <QFile>
#include <QTimer>
#include <QFileInfo>
#include <QMetaEnum>
#include <QNetworkAccessManager> FtpgetWindow::FtpgetWindow(QWidget *parent)
: QWidget(parent),
fileDownloadSize(),
lastDownloadSize(),
file(Q_NULLPTR)
{
downloadManager = new QNetworkAccessManager(this);
connect(downloadManager, SIGNAL(finished(QNetworkReply*)),SLOT(downloadFinishReply(QNetworkReply*))); //初始化超时检查定时器,30秒查询一次
timer = new QTimer;
connect(timer, SIGNAL(timeout()), SLOT(timeOut())); urlLabel = new QLabel;
urlLabel->setText(tr("Url:")); urlTextEdit = new QLineEdit;
urlLabel->setBuddy(urlTextEdit); runningTaskButton = new QPushButton;
runningTaskButton->setText("Run");
connect(runningTaskButton, SIGNAL(clicked(bool)), SLOT(updateTaskRunningState())); dirLoactionLabel = new QLabel;
dirLoactionLabel->setText(tr("Save Dir:")); dirTextEdit = new QLineEdit;
dirTextEdit->setReadOnly(true);
dirLoactionLabel->setBuddy(dirTextEdit); dirLocationButton = new QPushButton;
dirLocationButton->setText("Select Save Dir");
connect(dirLocationButton, SIGNAL(clicked(bool)), SLOT(updateSelectSaveDir())); runningTipLabel = new QLabel;
runningTipLabel->setText(tr("Runing task:")); progressBar = new QProgressBar;
runningTipLabel->setBuddy(progressBar); downlaodInfoLabel = new QLabel;
downlaodInfoLabel->setText(tr("Download Info:")); downloadInfoTextEdit = new QTextEdit;
downloadInfoTextEdit->setReadOnly(true);
downlaodInfoLabel->setBuddy(downloadInfoTextEdit); mainLayout = new QGridLayout;
mainLayout->setColumnStretch(, );
mainLayout->setColumnStretch(, );
mainLayout->setColumnStretch(, );
mainLayout->setMargin();
mainLayout->setColumnMinimumWidth(, ); mainLayout->addWidget(urlLabel, , );
mainLayout->addWidget(urlTextEdit, , );
mainLayout->addWidget(runningTaskButton, , );
mainLayout->addWidget(dirLoactionLabel, , );
mainLayout->addWidget(dirTextEdit, , );
mainLayout->addWidget(dirLocationButton, , );
mainLayout->addWidget(runningTipLabel, , , , );
mainLayout->addWidget(progressBar, , , , );
mainLayout->addWidget(downlaodInfoLabel, , , , );
mainLayout->addWidget(downloadInfoTextEdit, , , , );
setLayout(mainLayout); setFixedWidth();
setWindowTitle(tr("FpGet Window"));
} FtpgetWindow::~FtpgetWindow()
{
if(file != Q_NULLPTR)
{
file->deleteLater();
file = Q_NULLPTR;
}
//downloadManager的父对象是窗体,会自动进行析构
} /**
* @brief 进行下载超时判断,错误则发送超时信号
*/
void FtpgetWindow::timeOut()
{
if(lastDownloadSize != fileDownloadSize)
lastDownloadSize = fileDownloadSize;
else
emit downloadReply->error(QNetworkReply::TimeoutError); //下载超时,发送超时错误信号
} /**
* @brief 检查Url地址合法性
* @return
*/
bool FtpgetWindow::checkUrl()
{
url = QUrl(urlTextEdit->text());
if(!url.isValid())
{
downloadInfoTextEdit->append("Error: Invalid URL");
return false;
} if(url.scheme() != "ftp")
{
downloadInfoTextEdit->append("Error: URL must start with 'ftp:'");
return false;
} if (url.path().isEmpty()) {
downloadInfoTextEdit->append("Error: URL has no path");
return false;
}
return true;
} /**
* @brief 检查文件下载地址
* @return
*/
bool FtpgetWindow::checkSaveDir()
{
QString dir = dirTextEdit->text();
if(dir.isEmpty())
dir = QDir::currentPath() + "/Download/";
saveDir = QDir(dir); if(!saveDir.exists())
{
auto ok = saveDir.mkdir(dir);
if(!ok) return false;
}
return true;
} bool FtpgetWindow::createDownloadFile()
{
auto localFileName = QFileInfo(url.path()).fileName();
if (localFileName.isEmpty())
localFileName = "ftpget.out"; file = new QFile;
file->setFileName(saveDir.absoluteFilePath(localFileName));
if(!file->open(QIODevice::WriteOnly))
{
auto info = "Error: Cannot write file " + file->fileName()
+ ": " + file->errorString();
downloadInfoTextEdit->append(info);
return false;
}
return true;
} /**
* @brief 开始下载文件操作
*/
void FtpgetWindow::startDownloadFile()
{
if(!createDownloadFile()) return; if(timer->isActive())
timer->stop();
fileDownloadSize = lastDownloadSize = ; //重新设置定时器以及相关变量 downloadInfoTextEdit->append("Download file: " + url.fileName()); downloadReply = downloadManager->get(QNetworkRequest(url)); //分块获取文件信息,并写入文件中
connect(downloadReply, SIGNAL(readyRead()), SLOT(slotReadyRead())); //获取下载进度信息
connect(downloadReply, SIGNAL(downloadProgress(qint64,qint64)),
SLOT(downloadProgress(qint64,qint64))); //下载过程出错,进行报错处理(超时处理也是丢出超时信号,交由此槽函数进行处理)
connect(downloadReply, SIGNAL(error(QNetworkReply::NetworkError)),
SLOT(readReplyError(QNetworkReply::NetworkError))); timer->start( * ); //启动超时检查定时器,每30秒查询下载情况
} void FtpgetWindow::updateSelectSaveDir()
{
dirTextEdit->setText("");
QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"),
"C://",
QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks);
if(!dir.isEmpty())
dirTextEdit->setText(dir);
} void FtpgetWindow::updateTaskRunningState()
{
if(!checkUrl() || !checkSaveDir())
return; downloadInfoTextEdit->clear(); //清空信息栏 runningTaskButton->setEnabled(false);
dirLocationButton->setEnabled(false);
startDownloadFile();
} /**
* @brief 文件下载完成的清尾操作
* @param reply
*/
void FtpgetWindow::downloadFinishReply(QNetworkReply *reply)
{
file->waitForBytesWritten( * ); //等待文件写入结束
if( == file->size())
//此处下载失败,不再进行重新下载操作
downloadInfoTextEdit->append("Nothing be download.");
else
downloadInfoTextEdit->append("Download file success."); if(timer->isActive())
timer->stop(); //停止超时计时器 file->deleteLater();
file = Q_NULLPTR; reply->deleteLater();
reply = Q_NULLPTR; runningTaskButton->setEnabled(true);
dirLocationButton->setEnabled(true);
} void FtpgetWindow::slotReadyRead()
{
file->write(downloadReply->readAll());
fileDownloadSize = file->size(); //更新下载字节数
} /**
* @brief 下载异常,重新进行下载
* @param error
*/
void FtpgetWindow::readReplyError(QNetworkReply::NetworkError error)
{
auto metaEnum = QMetaEnum::fromType<QNetworkReply::NetworkError>();
//PS:字符串转换为枚举值
//Qt::Alignment alignment = (Qt::Alignment)metaEnum.keyToValue("Qt::AlignLeft");
//alignment = (Qt::Alignment)metaEnum.keysToValue("Qt::AlignLeft | Qt::AlignVCenter");
//枚举值转换为字符串
auto errStr = metaEnum.valueToKey(error);
downloadInfoTextEdit->append("Download file occur error: " + QString(errStr)); file->deleteLater();
file = Q_NULLPTR; downloadReply->deleteLater();
downloadReply = Q_NULLPTR; startDownloadFile(); //重新尝试下载文件
} void FtpgetWindow::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
if( != bytesTotal)
{
progressBar->setMaximum(bytesTotal);
progressBar->setValue(bytesReceived);
}
}

(1)超时操作:

在下载过程中,经常出现假死操作,因为不清楚如何进行续传操作,现有做法是取消当前下载任务并重新开始。

在启动下载操所时,启动定时器,每隔30秒记录当前下载数值和上一次记录的下载数值比较,如果相同,则可以认为在30秒内无操作,发送超时信号,断开连接重新开始下载任务。

(2)大文件下载:

现有仅测试了上百M的文件,可以在下载结束的时候,一次读取所有字节并写入文件,但是这样的压力比较大。

因此,当QNetworkReply发送信号告知有分段数据可供读取的时候,即读取并写入文件中。

(3)大文件上传:

调用put函数时,主要有两种方式,将文件信息读取出保存至QByteArray中,或者上传文件的操作指针。使用后者即可实现大型文件的上传操作。

(4)下载进度信息:

下载过程中,QNetworkReply会发送下载进度信息,用户可以根据此刷新QProgressBar控件,或者在命令行刷新进度条。

以下代码为在命令行实现进度条刷新操作,关键在于每次输出进度信息的时候,不要添加换行符,并且在输出信息头部添加"\r"即可。

 /**
* @brief 实现命令行下进度条,提示下载进度
* @param bytesReceived
* @param bytesTotal
*/
void FtpGet::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
int barLength = ;
int percent = int(qreal(bytesReceived) / qreal(bytesTotal) * barLength);
QString out = "\rPercent: " + QString(percent, '#') + QString(barLength - percent, ' ');
out += " " + QString::number(bytesReceived) + " / " + QString::number(bytesTotal);
std::cout << qPrintable(out) << std::flush;
}

> PS:
> 如果您觉得我的文章对您有帮助,可以扫码领取下红包或扫码支持(随意多少,一分钱都是爱),谢谢!

支付宝红包 | 支付宝 | 微信
-|-|-
![](https://img2018.cnblogs.com/blog/764719/201906/764719-20190624102014468-193165117.png) | ![](https://img2018.cnblogs.com/blog/764719/201906/764719-20190624102025867-1690450943.png) | ![](https://img2018.cnblogs.com/blog/764719/201906/764719-20190624101626318-627523959.png) |

使用QNetworkAccessManager实现Qt的FTP下载服务的更多相关文章

  1. C#本地文件下载以及FTP文件服务下载(以Pdf文件为例)

    一.C#实现本地文件下载 1.文件下载的路径  文件名称 以及文件下载之后要放的位置  这三个变量是必须要的 2.定义以下四个对象: FileWebRequest ftpWebRequest = nu ...

  2. [windows]快速从ftp下载最新软件包的批处理脚本

    背景 由于敏捷开发,快速迭代,我们项目一天会有三个版本,也就意味着我一天要去获取三次软件包.我负责服务端开发,所以我经常需要去拿最新的客户端.我们的客户端放置在一个公共的ftp上面.每天频繁登陆ftp ...

  3. 如何在Windows Server 2003中配置FTP站点服务

    前面写过一篇文章<怎样给你的网站注册一个好域名?> ,讲到“玉米”,笔者有很深的情节,也希望与大家交流“米事”,可以站内私信我或者直接回复文章. 有了好域名只是做网站的开始.我们还要买主机 ...

  4. centos 6.5下安装文件上传下载服务

    centos 6.5下安装文件上传下载服务 由于每次在CentOS中要下载一些配置文件到物理机,和上传一些文件到服务器,导致来回的开启ftp软件有点麻烦,这里我们可以使用文件上传下载服务,来解决上传和 ...

  5. ftp文件共享服务详解

     ftp 文件共享服务,文件的上传下载 跨平台,tcp协议 21号(命令端口) 20号(数据端口,主动模式) 默认情况 ftp服务运行被动模式 vsftpd:软件 非常安全的rpm -qi vsftp ...

  6. Qt开发环境下载和安装

    Qt是跨平台的图形开发库,目前由Digia全资子公司 Qt Company 独立运营,官方网址: http://www.qt.io/ 也可以访问Qt项目域名:http://qt-project.org ...

  7. 腾讯云,搭建 FTP 文件服务

    腾讯云,搭建 FTP 文件服务 腾讯云,搭建 FTP 文件服务 安装并启动 FTP 服务 任务时间:5min ~ 10min 安装 VSFTPD 使用 yum 安装 vsftpd: yum insta ...

  8. 基于 Ubuntu 搭建 FTP 文件服务

    搭建 FTP 文件服务 安装并启动 FTP 服务 任务时间:5min ~ 10min 安装 VSFTPD 使用 apt-get 安装 vsftpd: sudo apt-get install vsft ...

  9. 腾讯云:ubuntu搭建 FTP 文件服务

    搭建 FTP 文件服务 安装并启动 FTP 服务 任务时间:5min ~ 10min 安装 VSFTPD 使用 apt-get 安装 vsftpd: sudo apt-get install vsft ...

随机推荐

  1. AX2009 批处理作业中使用多线程---批量捆绑

    批量捆绑   由于Ax服务器中批处理线程是可以多个的,而实际批处理作业中线程往往只使用了一个 Class: /* 批量捆绑 */ /*class Code*/ public class DemoBat ...

  2. linux中du与df的区别和联系

    1,两者区别 du,disk usage,是通过搜索文件来计算每个文件的大小然后累加,du能看到的文件只是一些当前存在 的,没有被删除的.他计算的大小就是当前他认为存在的所有文件大小的累加和. df, ...

  3. vue history模式 apache配置

    我的服务器apache 版本是2.4.6 看文档上面说加那些代码,但是加上去重启服务器就不能重启,显示代码错误,然后百度查开启mod_rewrite这个重写URL 弄了半天也不会,百度上面的不知道是不 ...

  4. RPA答疑

    变量:部分主要对于工程中的变量进行管理和设置,支持手动拖拉至右侧画布 1全局变量:全局变量可以在整个工程中传递,被不同的子流程或函数进行调用,全局可见可调用 2 流程参数:只对子流程设置传入参数,供子 ...

  5. shell知识

    shell基本的语句 一:if语句 格式: if [ #条件的判断 ];then #执行的动作 fi 操作符 + 加 - 减 * 乘 /   除[取整数商] % 余[取余数] 数值的比较 参数 说明 ...

  6. LOJ-10092(最大半连通子图)

    题目连通:传送门 思路: 题目定义很清晰,然后就不会了QAQ…… 后来看了书,先缩点,然后再用拓扑排序找到最长的链子的节点数(因为缩点后所有点都是一个强连通分量,所以找最长的链子就是最大限度包含 点的 ...

  7. s6-8 TCP 拥塞控制

    TCP 拥塞控制  虽然网络层也试图管理拥塞,但是,大多数繁重的任务是由TCP来完成的,因为针对拥塞的真正解决方案是减慢数据率  分组守恒:当有一个老的分组离开之后才允许新的分组注入网络  TC ...

  8. crontab计划不执行问题

    问题现象:编写了一个自动释放磁盘空间的脚本,并将其加入到crontab中.crontab显示如下:# crontab -l10 5 * * * bash /home/backup/bin/clear. ...

  9. Ado.Net 注意事项

    Ado.Net同一个connection创建sqlCommand时,如果command要执行多个sql及其 params,这是如果某2个params中存在重名的话会报错, 例如sql1和params1 ...

  10. 2.0vue导出excel

    如果没有插件导入 import FileSaver from 'file-saver' import XLSX from 'xlsx'导入依赖 import FileSaver from 'file- ...