curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, callback);
static size_t callback(char* data, size_t size, size_t nmemb, void* buffer_in);
这个回调函数的原型一定要和官方文档里面的一样,否则可能会出各种奇怪的错误。注意,一定要是static函数,返回值、参数值一定要一样。回调的返回值一定要正确,不正确会导致回调停掉。
测试返回nmemb应该是正确的。
用了CURLOPT_WRITEFUNCTION,就一定要用CURLOPT_WRITEDATA
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &ftpfile);这里最后那个参数一定要是struct类型,这个参数在callback里面是它的第四个参数。可以自定义。
如果不用CURLOPT_WRITEFUNCTION,那么CURLOPT_WRITEDATA的参数一定是个FILE*类型。官方文档上介绍这个操作默认是用fwrite直接写文档的。
CURLOPT_DIRLISTONLY可以直接获取服务器的文件列表。
curl_global_init(CURL_GLOBAL_ALL); //全局初始化,而且只能调用一次
CURL_GLOBAL_ALL//这个flag是表示初始化一切可能,官网文档可以查到
curl_global_cleanup(); //全局回收资源
下载文件: //结构体也可以弄成C++文件流,只需要稍微修改一下下载的回调即可
struct downLoad
{
FILE* filestream;
std::string filename;
};
struct downLoad down_file;
{
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, “sftp://ip:port/filename”);
curl_easy_setopt(curl, CURLOPT_USERNAME, "username");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, down_file_call_back);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &down_file_);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
std::cout << "remote file error:" << res << std::endl;
curl_easy_strerror(res);
return -1;
}
curl_easy_cleanup(curl);
}
size_t CRemoteFileMan::down_file(char* data, size_t size, size_t nmemb, void* buffer_in)
{
struct downLoad* temp = (struct downLoad*)buffer_in;
if (temp->filestream == NULL && temp)
{
fopen_s(&temp->filestream, temp->filename.c_str(), "wb+");
if (!temp->filestream)
return - 1;
}
return fwrite(data, size, nmemb, temp->filestream);
}
获取远程服务器下的文件列表:
struct fileList
{
std::string filename;
};
struct fileList file_list;
{
CURL* curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, “sftp://ip:port/foldername/”);
curl_easy_setopt(curl, CURLOPT_USERNAME, "username");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, get_list);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &file_list);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
std::cout << "remote file error:" << res << std::endl;
curl_easy_strerror(res);
}
}
curl_easy_cleanup(curl);
}
size_t CRemoteFileMan::get_list(char* data, size_t size, size_t nmemb, void* buffer_in)
{
struct fileList* out = (struct fileList*)buffer_in;
out->filename.append(data);
return nmemb; //这个返回值不正确的话,回调会结束
}
判断远程文件是文件夹还是目录:
{
CURL* curl = curl_easy_init();
bool remoteFile = false;
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, “sftp://ip:port/foldername/”); // “sftp://ip:port/foldername/filename/”
curl_easy_setopt(curl, CURLOPT_USERNAME, "username");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); //设置这个参数的目的是看远程有没有这
//个指定的文件
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
remoteFile = false;
else
remoteFile = true;
curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L); //获取这个文件的远程列表,文件夹
//会返回一个列表,文件则出错,
//这样可以达到判断的目的
res = curl_easy_perform(curl);
if (res == CURLE_OK && remoteFile)
{
std::cout << "this is folder"<< std::endl;
return true;
}
}
std::cout << "this is file" << std::endl;
return false;
}
递归整个需要下载的目录,然后在本地指定的目录建立相应文件夹,下载完相应文件下的文件即可完成远程目录遍历下载。
//libcurl 下载ftp服务器全部文件 - CodeAntenna
这个链接是我在网上找到的一篇下载整个目录的文章,可以直接用,大致区别就是,这篇文章是将文件列表放在一个自己创建的txt文档内,然后用getline获取txt文档内的一行内容,然后判断是不是文件夹,文件夹就递归调用获取列表的函数并建立文件夹,否则下载该文件。
我自己则是想的将文件列表放在一个std::string字符串内,然后根据linux、windows的特性,分割字符串,获取列表,然后遍历列表,是文件夹就递归,不是文件夹就下载。