从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. GarageBand mac怎么剪切音频片段? GarageBand mac使用教程

    garageband mac智能控制轻松修饰声音资源库中任何乐器的音色,让你在世界各地都可以开始你的创意,让世界听到你的歌声.GarageBand mac剪切音频片段的操作小伙伴们也是需要掌握的,Ga ...

  2. 摹客iDoc 新功能“柔性工作流”,让设计随需而动

    摹客iDoc推出了全新“柔性工作流”,让协作设计自由流动,随需而动. 更高效.更自由的协作方式,赶快告诉你的团队吧~ “柔性工作流” VS “普通工作流” 普通工作流往往是将很多东西混杂在一起,并施以 ...

  3. HttpServletRequest字符集问题

    post中文处理 1post在spring里的设置web.xml文件 <!-- 字符处理 UTF8 --> <filter> <filter-name>encodi ...

  4. 对int数组排序

      // 排序-->小到大1     public void sortArray(int[] targetArr) {         long t = System.currentTimeMi ...

  5. Problem creating zip: Execution exce ption (and the archive is probably corrupt but I could not delete it): Java heap space -> [Help 1]

    今天mvn编译的时候报错:  [ERROR] Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.5.5:s ...

  6. Rabbimq 安装过程,还有踩得坑!centos 安装

    一 .安装erlang 1 添加yum 源,在/etc/yum.repos.d 下添加 rabbitmq-erlang.repo,内容如下 # In /etc/yum.repos.d/rabbitmq ...

  7. Spring的声明式事务管理<tx:advice/>

    <tx:advice/> 有关的设置 这一节里将描述通过 <tx:advice/> 标签来指定不同的事务性设置.默认的 <tx:advice/> 设置如下: 事务传 ...

  8. 20155205 郝博雅 Exp5 MSF基础应用

    20155205 郝博雅 Exp5 MSF基础应用 一.实验目标 本实践目标是掌握metasploit的基本应用方式,重点常用的三种攻击方式的思路.具体需要完成: 1.一个主动攻击实践,如ms08_0 ...

  9. Machine learning | 机器学习中的范数正则化

    目录 1. \(l_0\)范数和\(l_1\)范数 2. \(l_2\)范数 3. 核范数(nuclear norm) 参考文献 使用正则化有两大目标: 抑制过拟合: 将先验知识融入学习过程,比如稀疏 ...

  10. android踩坑日记1

    Android四大组件-活动.服务.广播.碎片 情况一 应用场景:定时从服务器获取数据,然后活动或者碎片中根据最新获得的数据,更新UI. 思考: 首先定时,想到定时器,推荐使用系统自带的AlertMa ...