1、FTP协议
FTP的中文名称是“文件传输协议”,是File Transfer Protocol三个英文单词的缩写。FTP协议是TCP/IP协议组中的协议之一,其传输效率非常高,在网络上传输大的文件时,经常采用该协议。
FTP协议又分为主动模式和被动模式,有关介绍看这里,本文不再赘述。
2、实现方式
QT中实现FTP传输功能有3种实现方式:
- Qt4 QFtp
- Qt5 QNetworkAccessManager
- POCO中的 FTPClientSession
第一种方式是QT中4.x中的实现方式,目前新版本中已经不再支持;第2种方式是目前qt中支持的实现方式;第三种属于第三方库。
QNetworkAccessManager 是Qt里面专门负责网络请求的模块,包含了http的post、get,还有一个put,而Qt5中要实现Ftp上传功能就通过put来完成,下载通过get来完成。下面的demo是这种方式实现的。
3、QNetworkAccessManager方式实现FTP
主要函数如下
QNetworkReply *put(const QNetworkRequest &request, QIODevice *data)
QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data)
QNetworkReply *put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
QNetworkReply *get(const QNetworkRequest &request)
FTP的传输功能封装了一个简单的类,头文件:
/*---------------ftpmanager.h---------------------*/
#ifndef FTPMANAGER_H
#define FTPMANAGER_H
#include <QUrl>
#include <QFile>
#include <QNetworkReply>
#include <QNetworkAccessManager>
class FtpManager : public QObject
{
Q_OBJECT
public:
explicit FtpManager(QObject *parent = 0);
// 设置地址和端口
void setHostPort(const QString &host, int port = 21)
{
m_pUrl.setHost(host);
m_pUrl.setPort(port);
}
// 设置登录 FTP 服务器的用户名和密码
void setUserInfo(const QString &userName, const QString &password);
// 上传文件
void put(const QString &fileName, const QString &path);
// 下载文件
void get(const QString &path, const QString &fileName);
signals:
void error(QNetworkReply::NetworkError err);
// 上传进度
void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
// 下载进度
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
private slots:
// 下载过程中写文件
void finished();
private:
QUrl m_pUrl;
QFile m_file;
QNetworkAccessManager m_manager;
};
#endif // FTPMANAGER_H
/*---------------ftpmanager.h---------------------*/
CPP文件
/*---------------ftpmanager.cpp---------------------*/
#include <QFileInfo>
#include "ftpmanager.h"
FtpManager::FtpManager(QObject *parent)
: QObject(parent)
{
// 设置协议
m_pUrl.setScheme("ftp");
}
// 设置登录 FTP 服务器的用户名和密码
void FtpManager::setUserInfo(const QString &userName, const QString &password)
{
m_pUrl.setUserName(userName);
m_pUrl.setPassword(password);
}
// 上传文件
void FtpManager::put(const QString &fileName, const QString &path)
{
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
m_pUrl.setPath(path);
QNetworkReply *pReply = m_manager.put(QNetworkRequest(m_pUrl), data);
connect(pReply, SIGNAL(uploadProgress(qint64, qint64)), this, SIGNAL(uploadProgress(qint64, qint64)));
connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SIGNAL(error(QNetworkReply::NetworkError)));
}
// 下载文件
void FtpManager::get(const QString &path, const QString &fileName)
{
QFileInfo info;
info.setFile(fileName);
m_file.setFileName(fileName);
m_file.open(QIODevice::WriteOnly | QIODevice::Append);
m_pUrl.setPath(path);
QNetworkReply *pReply = m_manager.get(QNetworkRequest(m_pUrl));
connect(pReply, SIGNAL(finished()), this, SLOT(finished()));
connect(pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SIGNAL(downloadProgress(qint64, qint64)));
connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SIGNAL(error(QNetworkReply::NetworkError)));
}
// 下载过程中写文件
void FtpManager::finished()
{
QNetworkReply *pReply = qobject_cast<QNetworkReply *>(sender());
switch (pReply->error())
{
case QNetworkReply::NoError :
{
m_file.write(pReply->readAll());
m_file.flush();
}
break;
default:
break;
}
m_file.close();
pReply->deleteLater();
}
/*---------------ftpmanager.cpp---------------------*/
部分实现
void QFtpUploadDlg::SetFtpLoginInfo(QString strIP, int iPort, QString strUser, QString strPsw)
{
m_strIP =strIP;
m_iPort = iPort;
m_strUser = strUser;
m_strPsw = strPsw;
}
void QFtpUploadDlg::on_uploadFileBtn_clicked()
{
if(!m_strFile.isEmpty())
{
m_pFtpManager->setHostPort(m_strIP,m_iPort);
m_pFtpManager->setUserInfo(m_strUser,m_strPsw);
m_pFtpManager->put(m_strFullName,"/test");
}
}
QString QFtpUploadDlg::getFilePath(QString filename)
{
QString strPath;
char szPath[256] ={0};
std::string str= filename.toStdString();
const char *tmpPath = str.c_str();
for(int i = filename.length(); i > 0; --i)
{
if(tmpPath[i-1] == '/')
{
memcpy(szPath,tmpPath,i-1);
break;
}
}
strPath.sprintf("%s",szPath);
return strPath;
}
Demo界面
下载 该程序的完整代码