FTP上传文件功能&&创建文件目录功能

本文介绍了如何在Qt中使用C++通过QNetworkAccessManager和QTcpSocket实现FTP上传功能,包括遍历文件夹、连接服务器、创建目录以及处理文件上传,特别提到了使用FtpUploader类处理文件上传过程中的细节和可能的优化点。
摘要由CSDN通过智能技术生成

要在Qt中使用C++实现FTP上传文件功能,首先需要考虑几个关键步骤:

  1. 遍历指定文件夹下的所有文件。
  2. 使用Qt的网络模块与FTP服务器建立连接。
  3. 根据需求上传文件,包括创建不存在的目录、处理同名文件的覆盖或重命名等。

我使用的是`QNetworkAccessManager` 实现文件上传,但`QNetworkAccessManager` 不支持创建目录等其他操作。

因此,创建 FTP 服务器上的目录将需要采取不同的方法。一种可能的解决方案是使用第三方库,或者直接使用 `QTcpSocket` 来发送 FTP 命令。这里我使用的就是 `QTcpSocket` 来发送 FTP 命令

然后,实现FTP上传功能的大致代码如下:

FtpUploader.h:

#ifndef FTPUPLOADER_H
#define FTPUPLOADER_H

#include <QObject>
#include <QNetworkAccessManager>

/**
* @class  FtpUploader
* @brief  负责通过FTP协议上传文件
*/
class FtpUploader : public QObject {
    Q_OBJECT

public:
    /**
	*  @brief  构造函数,接受FTP服务器的URL、用户名和密码
	*  @param[in] server			FTP服务器的URL
	*  @param[in] username		    用户名
	*  @param[in] password		    用户密码
	*/
    FtpUploader(const QString &server, const QString &username, const QString &password, QObject *parent = nullptr);

   /**
	*  @brief  上传指定目录下的所有文件
	*  @param[in] dirPath			文件夹地址
    *  @return 是否成功
	*/
    bool uploadDirectory(const QString &dirPath);

private:
    /**
	*  @brief  上传单个文件到FTP服务器。
	*  @param[in] filePath			本地文件的完整路径
	*  @param[in] remoteName	    文件在服务器上的存储位置和名称
    *  @return 是否成功
	*/
    bool uploadFile(const QString &filePath, const QString &remoteName);
    /**
	*  @brief  创建QTcpSocket连接
	*  @param[in] remoteName	    相对目录
	*/
	int setftpSocket(const QString& remoteName);
	/**
	*  @brief  在FTP服务器创建目录
	*  @param[in] socket			tcpsocket对象
	*  @param[in] fullPath	        目录
	*/
	void createDirectory(QTcpSocket& socket, const QString& fullPath);
    
    QNetworkAccessManager *manager; // 用于网络通信的管理器。
    QString serverUrl;              // FTP服务器的URL。
    QString username;               // FTP用户名。
    QString password;               // FTP密码。
};

#endif // FTPUPLOADER_H

FtpUploader.cpp

#include "FtpUploader.h"
#include <QDir>
#include <QFile>
#include <QFileInfoList>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QUrl>
#include <QDirIterator>
#include <QTcpSocket>
#include <QTextStream>
#include <QEventLoop>

FtpUploader::FtpUploader(const QString &server, const QString &username, const QString &password, QObject *parent)
    : QObject(parent), serverUrl(server), username(username), password(password) 
{
    manager = new QNetworkAccessManager(this); // 初始化网络访问管理器。
}

// 遍历目录并上传每个文件。
bool FtpUploader::uploadDirectory(const QString &dirPath) 
{
    QDir dir(dirPath);
    if (!dir.exists())
        return;

    QDir baseDir = dir;
	// 如果dirPath指向一个目录,向上移动一级来获取它的父目录作为基础路径
	if (dir.cdUp()) 
    {
		baseDir = dir.absolutePath();
	}

    bool bRet = false;
    //遍历目录及其所有子目录下的文件列表
	QDirIterator it(dirPath, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
	while (it.hasNext()) 
	{
		QString filePath = it.next();
		QFileInfo fileInfo(filePath);
		QString relativePath = baseDir.relativeFilePath(fileInfo.absoluteFilePath());
		bRet = uploadFile(fileInfo.absoluteFilePath(), relativePath);
        if (!bRet)
		{
			return bRet;
		}
	}
    return bRet;
}

// 处理文件上传。
bool FtpUploader::uploadFile(const QString &filePath, const QString &remoteName) 
{
    QFile *file = new QFile(filePath);
    if (!file->open(QIODevice::ReadOnly)) 
    {
        delete file;
        return false;
    }

    //创建目录
    setftpSocket(remoteName);

    QUrl url(serverUrl);
    url.setUserName(username);
    url.setPassword(password);
    url.setPath(remoteName);

    QNetworkRequest request(url);
    //put方法本质上是向服务器发送一个写入请求,如果同名文件存在,服务器通常会处理这个写入请求并覆盖文件。
    QNetworkReply *reply = manager->put(request, file);

    // 等待上传完成
	QEventLoop loop;
	QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
	loop.exec();
	// 检查上传结果
	if (reply->error() == QNetworkReply::NoError) 
	{
		qDebug() << "Upload successful for file:" << file->fileName();
		bRet = true;
	}
    else 
	{
		qDebug() << "Upload failed for file:" << file->fileName() << ", Error:" << reply->errorString();
		bRet = false;
	}
	file->close();
	file->deleteLater();
	reply->deleteLater();

	return bRet;
	
}

int FtpUploader::setftpSocket(const QString& remoteName)
{
	// 分割路径,得到各级目录和文件名
	QStringList pathParts = remoteName.split("/");

	// 去除最后一个元素(文件名),只保留目录结构
	pathParts.removeLast();

	// 重建目录路径
	QString directoryPath = pathParts.join("/");

	QTcpSocket ftpSocket;

	// 连接到 FTP 服务器
	ftpSocket.connectToHost("yourIP", 21);
	if (!ftpSocket.waitForConnected(30000)) {
		qDebug() << "Error connecting to server:" << ftpSocket.errorString();
		return -1;
	}

	// 等待欢迎消息
	if (!ftpSocket.waitForReadyRead(30000)) {
		qDebug() << "Error reading welcome message:" << ftpSocket.errorString();
		return -1;
	}
	qDebug() << "Server:" << QTextStream(&ftpSocket).readLine();

	// 登录到 FTP 服务器
	QTextStream(&ftpSocket) << "USER yourUsername\r\n";
	ftpSocket.waitForReadyRead(30000);
	QTextStream(&ftpSocket) << "PASS yourPassword\r\n";
	ftpSocket.waitForReadyRead(30000);

	// 创建多级目录
	createDirectory(ftpSocket, directoryPath);

	ftpSocket.close();
}

void FtpUploader::createDirectory(QTcpSocket& socket, const QString& fullPath) 
{
	QTextStream ftpStream(&socket);
	QStringList directories = fullPath.split("/", QString::SkipEmptyParts);

	QString currentPath;
	for (const QString& dir : directories) 
	{
		currentPath += "/" + dir;

		// 尝试改变到目标目录
		ftpStream << "CWD " << currentPath << "\r\n";
		ftpStream.flush();
		socket.waitForReadyRead();
		QString response = ftpStream.readLine();
		qDebug() << "CWD Response:" << response;

		// 如果改变目录失败,尝试创建目录
		if (response.startsWith("331")) 
		{ 
			ftpStream << "MKD " << currentPath << "\r\n";
			ftpStream.flush();
			socket.waitForReadyRead();
			qDebug() << "MKD Response:" << ftpStream.readLine();

			// 尝试改变到目标目录
			ftpStream << "CWD " << currentPath << "\r\n";
			ftpStream.flush();
			socket.waitForReadyRead();
			qDebug() << "CWD Response:" << ftpStream.readLine();
		}
		if (response.startsWith("550")|| response.startsWith("257")|| response.startsWith("250")) 
		{
			ftpStream << "MKD " << currentPath << "\r\n";
			ftpStream.flush();
			socket.waitForReadyRead();
			qDebug() << "MKD Response:" << ftpStream.readLine();
		}

	}

	// 最后,返回到根目录或初始目录
	ftpStream << "CWD /\r\n";
	ftpStream.flush();
	socket.waitForReadyRead();
	qDebug() << "Return to root Response:" << ftpStream.readLine();
}

替换 "yourIP", "yourUsername", "yourPassword"为你的 FTP 服务器信息。

调用FtpUploader:

我在界面中创建了一个按钮,然后点击按钮出现对话框选择目录,点击确定后进行文件传输。


//在.h文件中声明变量
FtpUploader *m_pUploader;


//在.cpp构造函数中做如下声明:
m_pUploader = new FtpUploader("ftp://172.20.46.19", "username", "password");


void TFormConclusion::on_pBtnUpload_clicked()
{
	// 打开文件对话框,选择目录
	QString dirPath = QFileDialog::getExistingDirectory(this, "选择目录", QString(), QFileDialog::ShowDirsOnly);
	if (!dirPath.isEmpty()) {
		// 文件上传
		
		bool bRet = m_pUploader->uploadDirectory(dirPath);
		 
		if (bRet)
		{
			QMessageBox::information(this,
				QString("提示"),
				QString("文件上传成功!"));
		}
		else
		{
			QMessageBox::information(this,
				QString("提示"),
				QString("文件上传失败!"));
		}
		
	}
}
	

这段代码提供了一个FtpUploader类,它可以遍历指定文件夹并在FTP服务器上创建文件夹,然后上传其中的文件到FTP服务器。另外,关于文件的覆盖或重命名,这通常取决于服务器的配置和行为。可以在上传前检查服务器上是否存在同名文件,并据此决定是覆盖还是重命名本地文件。

这个示例是一个基础版本,可能需要根据具体需求进行调整。例如,处理网络错误、上传进度反馈、异步上传、大文件处理等方面都可能需要额外的代码。此外,由于Qt 5.15之后FTP支持已从Qt中移除,如果您使用的是较新的Qt版本,可能需要使用第三方库如QFtp或自行实现FTP协议。

FTP(文件传输协议)是一种用于在网络上传输文件的标准协议。它可以让用户通过FTP客户端将文件从一个位置上传到另一个位置,或者从一个位置下载到本地计算机。 FTP上传是将文件从本地计算机上传到远程服务器的过程。首先,用户需要连接到FTP服务器,并使用正确的用户名和密码进行身份验证。一旦连接建立,用户可以使用FTP客户端在本地计算机上选择要上传的文件,然后将其传输到服务器上的目标位置。上传过程中,需要确保网络连接稳定,并且上传的文件在传输过程中不会被损坏。 FTP下载是将文件从远程服务器下载到本地计算机的过程。同样地,用户需要连接到FTP服务器,并进行身份验证。一旦连接建立,用户可以使用FTP客户端浏览服务器上可用的文件,并选择要下载的文件。下载过程中,文件将从服务器传输到本地计算机的指定目录中。 FTP上传和下载可以用于许多不同的场景。例如,网站管理员可以使用FTP上传网站文件到服务器上,以便在互联网上进行访问。用户也可以使用FTP下载软件、音频、视频等文件到自己的计算机上。此外,FTP还可以用于公司内部文件共享,团队成员可以通过FTP将文件传输给其他成员。 总而言之,FTP上传和下载是一种可靠的文件传输方法,允许用户在本地计算机和远程服务器之间传输文件。它在很多领域都有广泛的应用,为用户提供了便利和灵活性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值