curl使用ftp获取服务器上指定目录的所有文件集合以及下载
直接编译可用,注意修改测试main函数内的字符串,注释我觉得写的挺详细了,跑不起来的评论区可问
头文件
#ifndef FTP_DOWNLOAD_H
#define FTP_DOWNLOAD_H
#include <iostream>
#include <functional>
#include <memory>
#include <vector>
#include<cstdlib>
#include <ctime>
using namespace std;
using OutPutList = vector<string>;
#define FTPBODY "ftp-list"
struct FtpFile
{
string local;
FILE *stream;
};
class FtpDownloadder
{
public:
/**
* @brief Construct a new Ftp Downloadder object
*
* @param ip
* @param port
* @param username
* @param password
*/
FtpDownloadder(const char *ip,const char *port,const char *username,const char *password);
~FtpDownloadder();
/**
* @brief 获取指定文件夹下所有文件名
*
* @param folderName 指定文件夹名称
* (从登录用户家目录开始算,for example: /home/user/targetFolder , you can give a param with "targetFolder")
* @return OutPutList 该文件夹下的所有文件名集合,包含拓展名
*/
OutPutList getAllItem(const string& folderName);
/**
* @brief 更新本地缓存
*
* @param fileList ftp服务器上的文件集合
* @param remotFolderPath ftp服务器上的文件夹路径
* (从登录用户家目录开始算,for example: /home/user/targetFolder , you can give a param with "targetFolder")
* @param localCacheFolder 本地缓存文件夹
* @return true successful
* @return false faild
*/
bool flashLocalCache(const OutPutList& fileList, const string& remotFolderPath, const string& localCacheFolder);
/**
* @brief 下载文件
*
* @param filePath ftp服务器上的文件路径
* (从登录用户家目录开始算,for example: /home/user/targetFolder/test.tgz , you can give a param with "targetFolder/test.tgz")
* @param localFolderPath 本地存储的文件夹全路径,默认当前程序文件夹
* @return string 本地存储完整路径
*/
string downLoadFile(const string& filePath,const string& localFolderPath = "/home/root/test");
private:
string m_url;
string m_username;
string m_password;
};
std::shared_ptr<FtpDownloadder> createFtpPtr(const char *ip,const char *port,const char *username,const char *password);
#endif
cpp
#include "download.hpp"
#include <stdio.h>
#include <iostream>
#include <curl/curl.h>
#include <fstream>
#include <string.h>
#include <vector>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
using namespace std;
/* <DESC>
* Similar to ftpget.c but also stores the received response-lines
* in a separate file using our own callback!
* </DESC>
*/
static size_t
write_response(void *ptr, size_t size, size_t nmemb, void *data)
{
FILE *writehere = (FILE *)data;
return fwrite(ptr, size, nmemb, writehere);
}
/**
* @brief Get the File Name object
*
* @param content
* @param output
* @return true 是文件
* @return false 不是文件
*/
static bool getFileName(const string& content, char* output)
{
strncpy(output,content.c_str(),1);
if (strcmp(output,"d") == 0)
{
return false;
}
strncpy(output,content.c_str()+56,content.length()-56);
return true;
}
/**
* @brief 验证文件夹是否存在,不存在则创建
*
* @param path
* @return true
* @return false
*/
static bool checkFolderExistAndMKDIR(const string& path)
{
struct stat file_info;
if(stat(path.c_str(), &file_info) != 0)
{
string tt = "mkdir -p ";
tt+=path;
system(tt.c_str());
}
}
/**
* @brief 文件写入本地
*
* @param buffer
* @param size
* @param nmemb
* @param stream
* @return int
*/
int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
{
struct FtpFile *out=(struct FtpFile *)stream;
if(out && !out->stream)
{
/* open file for writing */
out->stream=fopen((out->local).c_str(), "ab+");
if(!out->stream)
{
cout << "failure, can't open "+out->local+" to write"<<endl;
return -1; /* failure, can't open file to write */
}
}
return fwrite(buffer, size, nmemb, out->stream);
}
FtpDownloadder::FtpDownloadder(const char *ip,const char *port,const char *username,const char *password)
{
m_url = "ftp://"+string(ip)+":"+string(port);
m_username = username;
m_password = password;
};
FtpDownloadder::~FtpDownloadder(){};
OutPutList FtpDownloadder::getAllItem(const string& folderName)
{
OutPutList outPutList;
// TODO
CURL *curl;
CURLcode res;
FILE *ftpfile;
/* local file name to store the file as */
ftpfile = fopen(FTPBODY, "wb"); /* b is binary, needed on win32 */
curl = curl_easy_init();
if(curl)
{
/* Get a file listing from ftp server */
string temp_url = m_url + "/"+folderName + "/";
curl_easy_setopt(curl, CURLOPT_URL, temp_url.c_str());
curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, ftpfile);
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
fclose(ftpfile);
return outPutList;
}
/* always cleanup */
curl_easy_cleanup(curl);
}
fclose(ftpfile); /* close the local file */
string content;
char buffer[312];
ifstream infile(FTPBODY);
if ( !infile)
{
cout<<"ifstream infile(\"ftp-list\") failed"<<endl;
return outPutList;
}
while (getline(infile,content))
{
memset(buffer,0,312);
auto temp_res = getFileName(content,buffer);
if (!temp_res)
{
continue;
}
outPutList.push_back(buffer);
}
infile.close();
return outPutList;
}
bool FtpDownloadder::flashLocalCache(const OutPutList& fileList, const string& remotFolderPath,const string& localCacheFolder)
{
checkFolderExistAndMKDIR(localCacheFolder);
// TODO
for(auto var : fileList)
{
string filePath = remotFolderPath +"/"+ var;
cout<<filePath<<endl;
downLoadFile(filePath,localCacheFolder);
}
return true;
}
string FtpDownloadder::downLoadFile(const string& filePath,const string& localFolderPath)
{
checkFolderExistAndMKDIR(localFolderPath);
string localPath = localFolderPath;
string t_remotPath;
char t_filename[255];
// TODO
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
t_remotPath = m_url+"/"+filePath;
memset(t_filename,0,255);
auto index = strrchr(filePath.c_str(),'/');
strcpy(t_filename,index+1);
localPath+=string(t_filename);
creat(localPath.c_str(),S_IRWXU);
int use_resume = 0;
curl_off_t local_file_len = -1 ;
struct stat file_info;
if(stat(localPath.c_str(), &file_info) == 0)
{
local_file_len = file_info.st_size;
use_resume = 1;
}
struct FtpFile ftpfile=
{
localPath, /* name to store the file as if successful */
NULL
};
// cout<< "ftpfile.local: "<<ftpfile.local<<endl;
curl = curl_easy_init();
if(curl)
{
curl_easy_setopt(curl, CURLOPT_URL, t_remotPath.c_str());
curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ftpfile);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return localPath;
}
std::shared_ptr<FtpDownloadder> createFtpPtr(const char *ip,const char *port,const char *username,const char *password){
return std::shared_ptr<FtpDownloadder>(new FtpDownloadder(ip,port,username,password));
}
main.cpp测试
#include "download.hpp"
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
auto dl=createFtpPtr("127.0.0.1","21","wangr","root");
int SW = argc>1?*argv[1] - '0' : 0;
// /home/用户名/qt_demo
string remotFolderPath = "qt_demo";
// /home/用户名/somewhere/qt_demo
// string remotFolderPath = "somewhere/qt_demo";
switch (SW)
{
case 0: dl->getAllItem(remotFolderPath);
break;
// /home/用户名/u/48205129.png
case 1: dl->downLoadFile("u/48205129.png","/home/wangr/d/");
// /home/用户名/somewhere/A/48205129.png
// case 1: dl->downLoadFile("somewhere/A/48205129.png","/home/wangr/d/");
break;
case 2: dl->flashLocalCache(dl->getAllItem(remotFolderPath),remotFolderPath,"/home/wangr/d/");
break;
default:
break;
}
return 0;
}