使用libcurl库实现FTP远程文件操作(windows和linux通用)

目录

写在前面

libcurl库windows下编译配置

libcurl c++常用操作

libcurl库实现FTP远程文件操作

头文件

向Ftp服务器上传文件

从Ftp服务器下载指定文件

从Ftp某个文件夹里面下载所有文件

远程在FTP上创建文件夹

获取FTP文件夹内所有文件名

解决文件名中空格、特殊字符无法出现错误

其他相关函数

包含功能为:

1、向Ftp服务器上传文件

2、从Ftp服务器下载特定文件

3、从Ftp某个文件夹里面下载所有文件

4、远程在FTP服务器指定位置创建文件夹

5、查看FTP服务器指定目录内所有文件名

解决了FTP上传/下载文件时,文件名有中文,有特殊字符时无法上传/下载的问题。

写在前面

可以直接运行的,包含上述全部功能的代码已经上传到github上了,下载文件,配置好自己的环境即可直接使用。代码中包含详细注释以及使用方式。

github链接:https://github.com/DylanYh2/FTPClient_libcurl.git

libcurl库windows下编译配置

windows系统编译libcurl库,并在visual studio2019/2022使用(win10,win11通用)

libcurl c++常用操作

libcurl c++常用操作

libcurl库实现FTP远程文件操作

头文件

#pragma once
#include<iostream>
#include<curl/curl.h>
#include<string>
#include<vector>
using namespace std;

class FtpManage
{
public:
	FtpManage();
	FtpManage(const string user, const string password, const string id);
	~FtpManage();
	
	/*
	*@Upload: 向Ftp服务器上传文件
	* @localFilePath:所上传的文件(精确到文件名),如"D:/ggbond/123.jpg"
	* @remoteDirectory:上传至Ftp的目录,如"/shjr/"
	* @remark:将123.jpg上传到Ftp服务器的"/shjr/"目录下,
	*/
	bool Upload(const char* localFilePath, const char* remoteDirectory);

	/*
	* @Download:从Ftp服务器下载特定文件
	* @remoteFilePath:所下载的文件(精确到文件名)如"/shjr/333.jpg"
	* @localDirectory:保存至本地目录,如"D:/ggbond/"
	* @remark:将FTp服务器/shjr目录下的333.jpg下载到本地D:/ggbond目录
	*/
	bool DownloadFile(const char* remoteFilePath, const char* localDirectory);

	/*
	* @DownloadAllFiles:从Ftp某个文件夹里面下载所有文件
	* @remoteFilePath:所下载的文件夹名称,如"/shjr/"
	* @localDirectory:保存至本地目录,如"D:/ggbond/"
	* @remark:将FTp服务器/shjr/目录里面下载所有文件到本地D:/ggbond/目录
	*/
	bool DownloadAllFiles(const char* remoteFilePath, const char* localDirectory);
	
	/*
	* @Createdir:创建文件夹
	* @directoryname:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录
	* 比如:"/ggbond/"
	*/
	bool Createdir(const char* directoryname);

	/*
	* @GetFilesName:提供获取FTP文件夹内所有文件名的接口
	* @filepath:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录
	* 比如:"/ggbond/"
	*/
	const std::vector<std::string>& GetFilesName(const string filepath);
	
private:
	/*
	* @SetURL:初始化URL
	*/
	void SetURL();

	/*
	* @UrlEncode:把含有特殊符号的文件名进行URL编码
	* @value:文件名
	* @"kunkunboy##  123"这种形式是无法传入curl的,需要转换一下
	*/
	std::string UrlEncode(const std::string& value);

	/*
	* @GEtFileNameFromPath:从路径中提取文件名并返回
	* @filePath:文件完整路径
	* @"D:/ggbond/123.jpg"->123.jpg
	*/
	std::string GetFileNameFromPath(const std::string& filePath);

	/*
	* @GetfilenameFromftp:获得FTP服务器上某个文件夹内所有文件名,如果文件夹内既有文件又有文件夹,则只会显示文件
	* @directoryname:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录
	*/
	bool GetfilenameFromftp(const string directoryname);
private:
	std::string Ftp_ip;									//Ftp服务器地址
	std::string User, Password;							//登录用户名及密码
	std::string _URL;
	std::vector<std::string> fNs;						//用于记录全部文件名
	CURL* curl;
};

向Ftp服务器上传文件

核心代码为:

    /*
	*@Upload: 向Ftp服务器上传文件
	* @localFilePath:所上传的文件(精确到文件名),如"D:/ggbond/123.jpg"
	* @remoteDirectory:上传至Ftp的目录,如"/shjr/"
	* @remark:将123.jpg上传到Ftp服务器的"/shjr/"目录下,
	*/
bool Upload(const char* localFilePath, const char* remoteDirectory);
{
    SetURL();
	_URL = Ftp_ip + remoteDirectory+ GetFileNameFromPath(localFilePath);
	curl_easy_setopt(curl, CURLOPT_URL, _URL.c_str());		// 设置访问的FTP地址
	if (curl)
	{
		FILE* fp = fopen(localFilePath, "rb");
		curl_off_t fsize = 0;
		if (fp)
		{
			fseek(fp, 0, SEEK_END);
			fsize = ftell(fp);			// 获取文件大小
			fseek(fp, 0, SEEK_SET);

			curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);				// 指定为上传文件模式
			curl_easy_setopt(curl, CURLOPT_READDATA, fp);			// 指定上传的文件是哪个
			curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, fsize);// 指定上传的文件大小

			CURLcode res = curl_easy_perform(curl);					// 开始上传
			if (res != CURLE_OK)
			{
				std::cout << "localFilePath: " << localFilePath << " upload failed!" << curl_easy_strerror(res) << std::endl;
				curl_easy_cleanup(curl);
				fclose(fp);
				return false;
			}
			else
			{
				std::cout << "localFilePath: " << localFilePath << " upload successfully!" << std::endl;
			}
			fclose(fp);
		}
		else
		{
			std::cout << "file: " << localFilePath << " open failed!" << std::endl;
			curl_easy_cleanup(curl);
			return false;
		}
	}
	curl_easy_cleanup(curl);
	return true;
}

从Ftp服务器下载指定文件

核心代码为:

	/*
	* @Download:从Ftp服务器下载特定文件
	* @remoteFilePath:所下载的文件(精确到文件名)如"/shjr/333.jpg"
	* @localDirectory:保存至本地目录,如"D:/ggbond/"
	* @remark:将FTp服务器/shjr目录下的333.jpg下载到本地D:/ggbond目录
	*/
bool FtpManage::DownloadFile(const char* remoteFilePath, const char* localDirectory)
{
	SetURL();
	_URL = Ftp_ip + UrlEncode(remoteFilePath);
	curl_easy_setopt(curl, CURLOPT_URL, _URL.c_str());		// 设置请求的URL
	if (curl)
	{
		FILE* fp = fopen((localDirectory + GetFileNameFromPath(remoteFilePath)).c_str(), "wb");
		if (fp)
		{
			// 设置文件写入地址
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
			// 执行任务
			CURLcode res = curl_easy_perform(curl);
			if (res != CURLE_OK)
			{
				std::cout << "DownLoad file:" << remoteFilePath << " failed! " << curl_easy_strerror(res) << std::endl;
				fclose(fp);
				curl_easy_cleanup(curl);
				return false;
			}
			else
			{
				std::cout << "DownLoad file:" << remoteFilePath << " successfully!" << std::endl;
				fclose(fp);
			}
		}
		else
		{
			std::cout << "file open failed!" << std::endl;
			curl_easy_cleanup(curl);		// 清除curl
			return false;
		}
	}
	curl_easy_cleanup(curl);
	return true;
}

从Ftp某个文件夹里面下载所有文件

/*
	* @DownloadAllFiles:从Ftp某个文件夹里面下载所有文件
	* @remoteFilePath:所下载的文件夹名称,如"/shjr/"
	* @localDirectory:保存至本地目录,如"D:/ggbond/"
	* @remark:将FTp服务器/shjr/目录里面下载所有文件到本地D:/ggbond/目录
	*/
bool FtpManage::DownloadAllFiles(const char* remoteFilePath, const char* localDirectory)
{
	if (GetfilenameFromftp(remoteFilePath))
	{
		for (const auto& fns : fNs)
		{
			std::string filename = remoteFilePath + fns;
			bool res = DownloadFile(filename.c_str(), localDirectory);
			if (res) continue;
			else
			{
				return false;
			}
		}
	}
	return true;
}

远程在FTP上创建文件夹

/*
	* @Createdir:创建文件夹
	* @directoryname:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录
	* 比如:"/ggbond/"
	*/
bool FtpManage::Createdir(const char* directoryname)
{
	if (directoryname == nullptr)
	{
		std::cout << "directoryname is NULL!" << std::endl;
		return false;
	}
	SetURL();
	_URL = Ftp_ip + UrlEncode(directoryname);
	curl_easy_setopt(curl, CURLOPT_URL, _URL.c_str());				// 指定url
	curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);	//如果目录不存在则创建一个
	CURLcode res = curl_easy_perform(curl);
	if (res != CURLE_OK)
	{
		std::cout << "Directory:" << directoryname << "create failed!" << curl_easy_strerror(res) << std::endl;
		curl_easy_cleanup(curl);		// 清理curl
		return false;
	}
	else
	{
		std::cout << "Create directory:" << directoryname << " successfully!" << std::endl;
	}
	curl_easy_cleanup(curl);
	return true;
}

获取FTP文件夹内所有文件名

/*
	* @GetFilesName:提供获取FTP文件夹内所有文件名的接口
	* @filepath:文件夹名称,可包含上级目录名,要以“/”结尾以表示目录
	* 比如:"/ggbond/"
	*/

//接收消息回调函数
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output)
{
	size_t totalSize = size * nmemb;
	output->append(static_cast<char*>(contents), totalSize);
	return totalSize;
}

// 获取ftp某个文件夹内文件名
bool FtpManage::GetfilenameFromftp(const std::string filePath)
{
	SetURL();
	std::string path = Ftp_ip + UrlEncode(filePath);
	std::string fileName;	// 文件名列表保存位置
	if (curl)
	{
		curl_easy_setopt(curl, CURLOPT_URL, path.c_str());	// 设置访问URL
		curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L);	// 设置只返回文件
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fileName);	// 设置只获取文件名列表
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);	// 设置get的回调函数
		if (curl_easy_perform(curl) == CURLE_OK)				//执行任务
		{
			fNs.clear();
			size_t startPos = 0, endPos = 0;
			while ((endPos = fileName.find('\n', startPos)) != std::string::npos )
			{
				std::string name = fileName.substr(startPos, endPos - startPos-1);
				fNs.emplace_back(name);
				startPos = endPos + 1;
			}
		}
	}
	else
	{
		return false;
	}
	curl_easy_cleanup(curl);
	return true;
}

// 获取FTP文件夹内所有文件名的接口函数
const std::vector<std::string>& FtpManage::GetFilesName(const string filepath)
{
	if (GetfilenameFromftp(filepath))
	{
		return fNs;
	}
	else
	{
		return std::vector<std::string>();
	}
}

解决文件名中空格、特殊字符无法出现错误

// 对文件名进行URL编码,否则文件名中有空格,特殊符合(#^...)会出现URL错误
std::string FtpManage::UrlEncode(const std::string &value) 
{
	CURL* curl = curl_easy_init();
	if (!curl) return "";
	char* output = curl_easy_escape(curl, value.c_str(), value.length());
	if (output) {
		std::string encoded(output);
		curl_free(output);
		curl_easy_cleanup(curl);
		return encoded;
	}
	curl_easy_cleanup(curl);
	return "";
}

其他相关函数

// 把带有路径的文件转换为文件名 D:/ggbond/123.jpg->123.jpg
std::string FtpManage::GetFileNameFromPath(const std::string& filePath)
{
	if (filePath == "") return filePath;

	//去除路径最后的空格
	string retPath;
	size_t lastBlank = filePath.find_last_not_of(' ');
	if (lastBlank != std::string::npos)
	{
		retPath = filePath.substr(0, lastBlank+1);
	}
	else
	{
		return "";
	}
	size_t lastSlashPos = retPath.find_last_of("/\\");
	if (lastSlashPos != std::string::npos)
	{
		return retPath.substr(lastSlashPos + 1);
	}
	else
	{
		// 如果没有找到斜杠或反斜杠,整个路径就是文件名
		return retPath;
	}
}

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值