#include "QtFtp.h" #include "LightLog.h" #include /* 构造函数 */ QtFtp::QtFtp(QObject *parent) { /* 设置协议 */ m_url.setScheme("ftp"); m_manager.setParent(this); /* 设置超时定时器 */ m_timer.setTimerType(Qt::PreciseTimer); m_timer.setSingleShot(true); connect(&m_timer,SIGNAL(timeout()),this,SLOT(do_timeout())); } QtFtp::~QtFtp() { if(m_file.isOpen()) { m_file.close(); } if(m_reply != nullptr) { m_reply->deleteLater(); m_reply = nullptr; } } /* 设置目标主机IP和端口 */ void QtFtp::setHostAndPort(const QString &host, int port) { m_url.setHost(host); m_url.setPort(port); } /* 设置目标设备的用户名和密码 */ void QtFtp::setUserPasswd(const QString &user, const QString &pw) { m_url.setUserName(user); m_url.setPassword(pw); } /** * @brief 上传文件 * @param file 要上传的文件名 * @param path 目标计算机存放文件的路径 */ void QtFtp::putFile(const QString &fileName, const QString &farPath) { m_isFinished = false; m_result = false; m_fileUpload.setFileName(fileName); if(!m_fileUpload.open(QFile::ReadOnly)) { QLOG_WARN("open file failed , file path : " + fileName); return; } m_url.setPath(farPath); m_reply = m_manager.put(QNetworkRequest(m_url),&m_fileUpload); /* 将信号进行一次转发 */ connect(m_reply,SIGNAL(uploadProgress(qint64,qint64)),this,SIGNAL(signal_uploadProgress(qint64,qint64))); /* 连接信号和槽 */ connect(m_reply,SIGNAL(finished()),this,SLOT(do_uploadFinished())); connect(m_reply,SIGNAL(uploadProgress(qint64,qint64)),this,SLOT(do_uploadProgress(qint64,qint64))); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SIGNAL(signal_error(QNetworkReply::NetworkError))); #endif } /** * @brief 重载函数,上传文件,直接上传内存数据 * * @param data 需要上传的数据 * @param farPath 远程文件名 */ void QtFtp::putFile(const QByteArray& data,const QString& farPath) { m_isFinished = false; m_result = false; m_url.setPath(farPath); m_reply = m_manager.put(QNetworkRequest(m_url),data); /* 将信号进行一次转发 */ connect(m_reply,SIGNAL(uploadProgress(qint64,qint64)),this,SIGNAL(signal_uploadProgress(qint64,qint64))); /* 连接信号和槽 */ connect(m_reply,SIGNAL(finished()),this,SLOT(do_uploadFinished())); connect(m_reply,SIGNAL(uploadProgress(qint64,qint64)),this,SLOT(do_uploadProgress(qint64,qint64))); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SIGNAL(signal_error(QNetworkReply::NetworkError))); #endif } /** * @brief QtFtp::getFile * @param fileName 本机文件路径和文件名 * @param path 目标文件路径 */ void QtFtp::getFile(const QString &fileName,const QString &srcPath) { m_isFinished = false; m_result = false; m_file.setFileName(fileName); if(!m_file.open(QFile::WriteOnly | QFile::Truncate)) { QLOG_WARN("open file failed , file path : " + fileName); return; } m_url.setPath(srcPath); m_reply = m_manager.get(QNetworkRequest(m_url)); /* 转发信号 */ connect(m_reply,SIGNAL(downloadProgress(qint64,qint64)),this,SIGNAL(signal_downloadProgress(qint64,qint64))); /* 连接信号和槽 */ connect(m_reply,SIGNAL(finished()),this,SLOT(do_downloadFinished())); connect(m_reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(do_downloadProgress(qint64,qint64))); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SIGNAL(signal_error(QNetworkReply::NetworkError))); #endif } /* 下载文件,直接下载到内存,路径是相对路径,不包含前面的IP地址和端口 */ void QtFtp::getFile(QByteArray& data,const QString& srcPath) { m_isFinished = false; m_result = false; m_downloadData = &data; m_url.setPath(srcPath); m_reply = m_manager.get(QNetworkRequest(m_url)); /* 转发信号 */ connect(m_reply,SIGNAL(downloadProgress(qint64,qint64)),this,SIGNAL(signal_downloadProgress(qint64,qint64))); /* 连接信号和槽 */ connect(m_reply,SIGNAL(finished()),this,SLOT(do_downloadFinishedToData())); connect(m_reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(do_downloadProgress(qint64,qint64))); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SIGNAL(signal_error(QNetworkReply::NetworkError))); #endif } /** * @brief 等待完成,同时设置超时时间,超时后,断开reply的信号和槽的连接 * 参数设置为0表示查询是否完成,设置为-1表示一直等待 * * @param msecs 超时时间 * @arg -1 一直等待,将会阻塞在这里 * @arg 0 查询是否完成 * @arg 正整数,等待完成的时间,设置完成之后再次设置,会覆盖之前的设置 * @arg < -1,阻塞等待传入的值的绝对值时间 * @return true 上传或下载完成 * @return false 上传或下载进行中 */ bool QtFtp::waitFinished(int msecs) { if(msecs == 0) { return m_isFinished; } else if(msecs == -1) { QEventLoop loop; connect(this, &QtFtp::signal_uploadState, &loop, &QEventLoop::quit); connect(this, &QtFtp::signal_downloadState, &loop, &QEventLoop::quit); loop.exec(); return true; } else if (msecs > 0) { m_timer.start(msecs); return m_isFinished; } else if(msecs < -1) { QEventLoop loop; connect(this, &QtFtp::signal_uploadState, &loop, &QEventLoop::quit); connect(this, &QtFtp::signal_downloadState, &loop, &QEventLoop::quit); m_timer.start(-msecs); connect(&m_timer, &QTimer::timeout, &loop, &QEventLoop::quit); loop.exec(); return false; } return m_isFinished; } /** * @brief 获取结果 * * @return int * @arg -1 上传或下载失败 * @arg 0 上传或下载成功 */ bool QtFtp::getResult() { return m_result; } /* 上传完成 */ void QtFtp::do_uploadFinished() { if(m_timer.isActive()) { m_timer.stop(); } if(m_reply->error() == QNetworkReply::NoError) { m_result = true; emit signal_uploadState(true); QLOG_INFO("----- FTP upload success -----"); } else { QLOG_WARN("FTP upload failed : " + m_reply->errorString()); emit signal_uploadState(false); } m_fileUpload.close(); m_reply->deleteLater(); m_reply = nullptr; m_isFinished = true; } /* 创建目录 */ bool QtFtp::createDir(const QString& path) { m_isFinished = false; m_result = false; QNetworkRequest request; QUrl url; url.setHost(m_url.host()); url.setPort(m_url.port()); url.setUserName(m_url.userName()); url.setPassword(m_url.password()); url.setPath(path); QLOG_DEBUG("create dir : " + url.path()); request.setUrl(url); request.setRawHeader("Content-Type", "application/x-www-form-urlencoded"); QByteArray data; data.append("command=MKD"); m_reply = m_manager.post(request,data); /* 连接信号和槽 */ connect(m_reply,SIGNAL(finished()),this,SLOT(do_finished())); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SIGNAL(signal_error(QNetworkReply::NetworkError))); #endif return true; } /** * @brief 完成,保存文件 * 这里采用逐步读取文件内容,因为QByteArray最多存储大约2GB的数据 * */ void QtFtp::do_downloadFinished() { if(m_timer.isActive()) { m_timer.stop(); } if(!m_file.isOpen()) { m_file.open(QFile::WriteOnly | QFile::Truncate); } if(m_reply->error() == QNetworkReply::NoError) { while(!m_reply->atEnd()) { /* 每次读取10MB */ QByteArray data = m_reply->read(10485760); quint64 writenBytes = m_file.write(data); QLOG_DEBUG("write file : " + QString::number(writenBytes)); if(writenBytes != data.size()) { QLOG_WARN("FTP download failed: write file failed"); emit signal_downloadState(false); m_result = false; break; } } m_file.flush(); emit signal_downloadState(true); m_result = true; QLOG_DEBUG("----- FTP download success -----"); }else { QLOG_WARN("FTP download failed:" + m_reply->errorString()); /* 下载失败就删除创建的文件 */ m_file.remove(); emit signal_downloadState(false); } m_file.close(); m_reply->deleteLater(); m_reply = nullptr; m_isFinished = true; } /* 下载完成,保存数据 */ void QtFtp::do_downloadFinishedToData() { if(m_timer.isActive()) { m_timer.stop(); } if(m_reply->error() == QNetworkReply::NoError) { *m_downloadData = m_reply->readAll(); emit signal_downloadState(true); m_result = true; QLOG_DEBUG("----- FTP download success -----"); }else { QLOG_WARN("FTP download failed:" + m_reply->errorString()); emit signal_downloadState(false); } m_downloadData = nullptr; m_reply->deleteLater(); m_reply = nullptr; m_isFinished = true; } /* 上传进度 */ void QtFtp::do_uploadProgress(qint64 bytesSent, qint64 bytesTotal) { QLOG_DEBUG("sent / total : " + QString::number(bytesSent) + " / " + QString::number(bytesTotal)); } /* 下载进度 */ void QtFtp::do_downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { QLOG_DEBUG("received / total : " + QString::number(bytesReceived) + " / " + QString::number(bytesTotal)); } /* ftp其他任务完成槽函数 */ void QtFtp::do_finished() { if(m_timer.isActive()) { m_timer.stop(); } m_isFinished = true; if(m_reply->error() == QNetworkReply::NoError) { QLOG_INFO("----- FTP operation success -----"); m_result = true; }else { QLOG_WARN("FTP operation failed : " + m_reply->errorString()); m_result = false; } m_reply->deleteLater(); m_reply = nullptr; m_isFinished = true; } /* 定时器超时函数 */ void QtFtp::do_timeout() { if(m_reply != nullptr) { m_reply->abort(); m_reply->deleteLater(); m_reply = nullptr; m_result = false; } emit signal_uploadState(false); emit signal_downloadState(false); } /* ftp发送错误槽函数 */ #if defined (QT_VERSION) && QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) void QtFtp::do_ftpReplyError(QNetworkReply::NetworkError error) { if(error == QNetworkReply::NoError) { QLOG_INFO("FTP发送成功"); } else { QLOG_WARN("FTP发送失败:" + QString::number(error)); } } #endif