使用QNetworkAccessManager实现FTP上传下载功能

20 篇文章 1 订阅
16 篇文章 0 订阅

自己写了一份FTP的代码,可以上传下载单文件,上传下载多文件,上传目录所有文件,但是下载目录的功能有问题,接口里代码规范也没做(如果有大佬提供修改方案就更好了),代码直接复制可用,留给有需要的人。

#pragma once

#include <QObject>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QFile>
#include <QTcpSocket>
#include <QMap>

class CFtpMgr : public QObject
{
    Q_OBJECT

public:
    CFtpMgr(QObject* parent = nullptr);
    ~CFtpMgr();

    void SetFtpAuthority(const QString& strHost, const QString& strName, const QString& strPassword, quint16 nPort = 21);

    void DownloadFile(const QString& strRemoteFilePath, const QString& strLocalDir);
    void UploadFile(const QString& strLocalFilePath, const QString& strRemoteDir);
    void DownloadFiles(const QStringList& listRemoteFilePaths, const QString& strLocalDir);
    void UploadFiles(const QStringList& listLocalFilePaths, const QString& strRemoteDir);
    void DownloadDir(const QString& strRemoteDir, const QString& strLocalDir);
    void UploadDir(const QString& strLocalDir, const QString& strRemoteDir);

signals:
    void SigDownloadProgress(qint64 nReceived, qint64 nTotal);
    void SigUploadProgress(qint64 nReceived, qint64 nTotal);

public slots:
    void SlotDownloadProgress(qint64 nReceived, qint64 nTotal);
    void SlotDownloadError(QNetworkReply::NetworkError eError);
    void SlotDownloadFinished();

    void SlotUploadProgress(qint64 nReceived, qint64 nTotal);
    void SlotUploadError(QNetworkReply::NetworkError eError);
    void SlotUploadFinished();

private:
    void EnsureRemotePathExists(const QString& strRemoteDir);
    void RecursiveDownloadDir(const QString& strRemoteDir, const QString& strLocalDir);
    void RecursiveUploadDir(const QString& strLocalDir, const QString& strRemoteDir);

private:
    QUrl m_url;
    QNetworkAccessManager m_manager;
    QTcpSocket m_socket;

    QMap<QNetworkReply*, QFile*> m_mapGetReplies;
    QMap<QNetworkReply*, QFile*> m_mapPutReplies;
};
#include "FtpMgr.h"
#include <QDir>
#include <QDebug>
#include <QTcpServer>

CFtpMgr::CFtpMgr(QObject* parent)
	: QObject(parent)
{
	m_url.setScheme("ftp");
}

CFtpMgr::~CFtpMgr()
{
	qDeleteAll(m_mapGetReplies);
	qDeleteAll(m_mapPutReplies);
}

void CFtpMgr::SetFtpAuthority(const QString& strHost, const QString& strName, const QString& strPassword, quint16 nPort)
{
	m_url.setHost(strHost);
	m_url.setUserName(strName);
	m_url.setPassword(strPassword);
	m_url.setPort(nPort);
}

void CFtpMgr::DownloadFile(const QString& strRemoteFilePath, const QString& strLocalDir)
{
	const QString strSaveFileName = strLocalDir + "/" + QFileInfo(strRemoteFilePath).fileName();

	QFile* pFile = new QFile(strSaveFileName, this);
	if (pFile->open(QIODevice::WriteOnly))
	{
		m_url.setPath(strRemoteFilePath);
		QNetworkReply* pReply = m_manager.get(QNetworkRequest(m_url));
		m_mapGetReplies[pReply] = pFile;

		connect(pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(SlotDownloadProgress(qint64, qint64)));
		connect(pReply, SIGNAL(finished()), this, SLOT(SlotDownloadFinished()));
		connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(SlotDownloadError(QNetworkReply::NetworkError)));
	}
	else
	{
		delete pFile;
	}
}

void CFtpMgr::UploadFile(const QString& strLocalFilePath, const QString& strRemoteDir)
{
	EnsureRemotePathExists(strRemoteDir);

	QFile* pFile = new QFile(strLocalFilePath, this);
	if (pFile->open(QIODevice::ReadOnly))
	{
		const QString strSaveFileName = strRemoteDir + "/" + QFileInfo(strLocalFilePath).fileName();
		m_url.setPath(strSaveFileName);

		QNetworkReply* pReply = m_manager.put(QNetworkRequest(m_url), pFile);
		m_mapPutReplies[pReply] = pFile;

		connect(pReply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(SlotUploadProgress(qint64, qint64)));
		connect(pReply, SIGNAL(finished()), this, SLOT(SlotUploadFinished()));
		connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(SlotUploadError(QNetworkReply::NetworkError)));
	}
	else
	{
		delete pFile;
	}
}

void CFtpMgr::DownloadFiles(const QStringList& listRemoteFilePaths, const QString& strLocalDir)
{
	foreach(const QString & remoteFilePath, listRemoteFilePaths)
	{
		DownloadFile(remoteFilePath, strLocalDir);
	}
}

void CFtpMgr::UploadFiles(const QStringList& listLocalFilePaths, const QString& strRemoteDir)
{
	EnsureRemotePathExists(strRemoteDir);

	foreach(const QString & localFilePath, listLocalFilePaths)
	{
		UploadFile(localFilePath, strRemoteDir);
	}
}

void CFtpMgr::DownloadDir(const QString& strRemoteDir, const QString& strLocalDir)
{
	QDir localDir(strLocalDir);
	if (!localDir.exists())
	{
		localDir.mkpath(".");
	}
	RecursiveDownloadDir(strRemoteDir, strLocalDir);
}

void CFtpMgr::UploadDir(const QString& strLocalDir, const QString& strRemoteDir)
{
	RecursiveUploadDir(strLocalDir, strRemoteDir);
}

void CFtpMgr::EnsureRemotePathExists(const QString& strRemoteDir)
{
	m_socket.connectToHost(m_url.host(), m_url.port(21));
	if (m_socket.waitForConnected())
	{
		m_socket.write("USER " + m_url.userName().toUtf8() + "\r\n");
		m_socket.waitForReadyRead();
		m_socket.write("PASS " + m_url.password().toUtf8() + "\r\n");
		m_socket.waitForReadyRead();
		m_socket.write("MKD " + strRemoteDir.toUtf8() + "\r\n");
		m_socket.waitForReadyRead();
		m_socket.disconnectFromHost();
	}
}

void CFtpMgr::RecursiveDownloadDir(const QString& strRemoteDir, const QString& strLocalDir)
{
	// 接口不可用

	return;

	// 以下为测试代码
	m_url.setPath(m_url.path() + strRemoteDir);
	QNetworkRequest listRequest(m_url);

	QNetworkReply* listReply = m_manager.get(listRequest);
	connect(listReply, &QNetworkReply::finished, listReply, [=]()
		{
			if (listReply->error() == QNetworkReply::NoError)
			{
				QString list = listReply->readAll();
				QStringList lines = list.split("\n");

				QStringList remoteFiles;
				QStringList remoteDirs;

				for (const QString& line : lines)
				{
					if (line.trimmed().isEmpty())
					{
						continue;
					}

					// Assuming Unix-style listing
					char entryType = line.at(0).toLatin1();
					QString entryPath = line.mid(55).trimmed();

					if (entryType == '-')
					{
						remoteFiles.append(entryPath);
					}
					else if (entryType == 'd')
					{
						remoteDirs.append(entryPath);
					}
				}

				QStringList remoteFilePaths;
				for (const QString& remoteFile : remoteFiles)
				{
					remoteFilePaths.append(strRemoteDir + remoteFile);
				}

				DownloadFiles(remoteFilePaths, strLocalDir);

				for (const QString& remoteDir : remoteDirs)
				{
					QString subRemoteFolderPath = strRemoteDir + remoteDir + "/";
					QString subLocalFolderPath = strLocalDir + remoteDir + "/";
					RecursiveDownloadDir(subRemoteFolderPath, subLocalFolderPath);
				}
			}
			else
			{
				qDebug() << "Error listing directory:" << listReply->errorString();
			}

			listReply->deleteLater();
		});
}

void CFtpMgr::RecursiveUploadDir(const QString& strLocalDir, const QString& strRemoteDir)
{
	QDir localDir(strLocalDir);
	if (!localDir.exists())
	{
		return;
	}

	EnsureRemotePathExists(strRemoteDir);

	QFileInfoList fileInfoList = localDir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
	for (const QFileInfo& fileInfo : fileInfoList)
	{
		QString localPath = fileInfo.absoluteFilePath();
		QString remotePath = strRemoteDir + "/" + fileInfo.fileName();

		if (fileInfo.isDir())
		{
			RecursiveUploadDir(localPath, remotePath);
		}
		else if (fileInfo.isFile())
		{
			UploadFile(localPath, strRemoteDir);
		}
	}
}

void CFtpMgr::SlotDownloadProgress(qint64 nReceived, qint64 nTotal)
{
	emit SigDownloadProgress(nReceived, nTotal);
}

void CFtpMgr::SlotDownloadError(QNetworkReply::NetworkError eError)
{
	qDebug() << "Download Error: " << eError;
	QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
	if (pReply)
	{
		if (m_mapGetReplies.contains(pReply))
		{
			QFile* pFile = m_mapGetReplies.value(pReply);
			if (pFile)
			{
				pFile->close();
				delete pFile;
			}
			m_mapGetReplies.remove(pReply);
		}
		pReply->deleteLater();
	}
}

void CFtpMgr::SlotDownloadFinished()
{
	QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
	if (pReply)
	{
		if (m_mapGetReplies.contains(pReply))
		{
			QFile* pFile = m_mapGetReplies.value(pReply);
			if (pFile)
			{
				pFile->write(pReply->readAll());
				pFile->close();
				delete pFile;
			}
			m_mapGetReplies.remove(pReply);
		}
		pReply->deleteLater();
	}
}

void CFtpMgr::SlotUploadProgress(qint64 nReceived, qint64 nTotal)
{
	emit SigUploadProgress(nReceived, nTotal);
}

void CFtpMgr::SlotUploadError(QNetworkReply::NetworkError eError)
{
	qDebug() << "Upload Error: " << eError;
	QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
	if (pReply)
	{
		if (m_mapPutReplies.contains(pReply))
		{
			QFile* pFile = m_mapPutReplies.value(pReply);
			if (pFile)
			{
				pFile->close();
				delete pFile;
			}
			m_mapPutReplies.remove(pReply);
		}
		pReply->deleteLater();
	}
}

void CFtpMgr::SlotUploadFinished()
{
	QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
	if (pReply)
	{
		if (m_mapPutReplies.contains(pReply))
		{
			QFile* pFile = m_mapPutReplies.value(pReply);
			if (pFile)
			{
				pFile->close();
				delete pFile;
			}
			m_mapPutReplies.remove(pReply);
		}
		pReply->deleteLater();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值