#include "CurlFtp.h" #include #include #include /* 是否有初始化实例,主要用于静态函数调用curl_global_cleanup()函数前判断,有实例就不调用 */ static bool hasInstace = false; /* ================================================================================== * *********************************** 全局函数 ************************************* * ================================================================================== */ /** * @brief 写入回调函数 * * @param contents curl的数据缓冲区 * @param size 数据大小,单位是size_t * @param nmemb size_t的单位字节数 * @param s 用户提供的字符串 * @return size_t 总共获取到的数据大小,单位是字节 */ static size_t writeStringCallback(void *contents, size_t size, size_t nmemb, std::string *s) { size_t newLength = size*nmemb; size_t oldLength = s->size(); try { s->resize(oldLength + newLength); } catch(std::bad_alloc &e) { //handle memory problem return 0; } std::copy((char*)contents,(char*)contents+newLength,s->begin()+oldLength); return size*nmemb; } /** * @brief 写入回调函数,listFiles需要调用 * * @param buffer curl下载回来的数据 * @param size 数据大小 * @param nmemb 数据单位字节数 * @param userp 用户传进来的容器 * @return int 返回拷贝的字节数 */ static int writeStringListCallback(void* buffer, size_t size, size_t nmemb, void* userp) { std::vector* fileList = static_cast*>(userp); std::string line(static_cast(buffer), size * nmemb); // printf("line = %s\n", line.c_str()); fileList->push_back(line); return size * nmemb; } /* ================================================================================== * *********************************** 成员函数 ************************************* * ================================================================================== */ CurlFtp::CurlFtp() { /* 调用初始化函数,这个函数可以重复调用 */ curl_global_init(CURL_GLOBAL_DEFAULT); /* 初始化curl */ m_curl = curl_easy_init(); hasInstace = true; } CurlFtp::~CurlFtp() { /* 清理curl */ curl_easy_cleanup(m_curl); curl_global_cleanup(); hasInstace = false; } /* 检查文件夹是否存在,不确定好不好用 */ // bool CurlFtp::isDirExists(const std::string &ftpUrl, const std::string &username, const std::string &password) // { // CURL *curl; // CURLcode res; // bool result = false; // std::string retList; // curl_global_init(CURL_GLOBAL_DEFAULT); // curl = curl_easy_init(); // if(curl) // { // curl_easy_setopt(curl, CURLOPT_URL, ftpUrl.c_str()); // curl_easy_setopt(curl, CURLOPT_USERNAME, username.c_str()); // curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); // // curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L); // We only want the directory listing // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); // curl_easy_setopt(curl, CURLOPT_WRITEDATA, &retList); // res = curl_easy_perform(curl); // // printf("res = %d\n", res); // if(res != CURLE_OK) // { // fprintf(stderr, "getDirList() failed, error code %d, :%s\n",res, curl_easy_strerror(res)); // } // else // { // // std::cout << "Directory list: \n" << retList << std::endl; // } // curl_easy_cleanup(curl); // } // curl_global_cleanup(); // return result; // } /* 使用正则表达式提取出文件夹 */ // bool CurlFtp::extractDirectories(const std::string& responseString) // { // std::regex directoryRegex(R"(^d.*\s(\S+)$)"); // std::smatch match; // std::istringstream retStream(responseString); // std::string line; // while (std::getline(retStream, line)) // { // if (std::regex_match(line, match, directoryRegex)) // { // std::cout << "Directory: " << match[1] << std::endl; // } // } // return true; // } /** * @brief 列出FTP文件夹 * * @param ftpUrl 需要列出文件夹的FTP地址 * @param username * @param password * @return std::string */ std::string CurlFtp::listDir(const std::string &ftpUrl, const std::string &username, const std::string &password) { CURL *curl; CURLcode res; bool result = false; std::string retList; /* 1. 初始化curl,这个函数需要在调用任何curl函数之前 */ curl_global_init(CURL_GLOBAL_DEFAULT); /* 2. 获取一个curl句柄 */ curl = curl_easy_init(); if(curl) { /* 3. 设置curl选项 */ curl_easy_setopt(curl, CURLOPT_URL, ftpUrl.c_str()); curl_easy_setopt(curl, CURLOPT_USERNAME, username.c_str()); curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); // curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L); // We only want the directory listing curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeStringCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &retList); /* 4. 发送信息,一直等待知道返回 */ res = curl_easy_perform(curl); // printf("res = %d\n", res); if(res != CURLE_OK) { fprintf(stderr, "getDirList() failed, error code %d, :%s\n",res, curl_easy_strerror(res)); } else { // std::cout << "Directory list: \n" << retList << std::endl; } /* 5. 清理curl */ curl_easy_cleanup(curl); } if(hasInstace == false) { curl_global_cleanup(); } return retList; } /* 列出文件夹中的所有文件 */ bool CurlFtp::listFiles(const std::string &ftpUrl, const std::string &username, const std::string &password, std::vector& fileList) { CURL *curl; CURLcode res; bool result = false; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, (ftpUrl).c_str()); curl_easy_setopt(curl, CURLOPT_USERNAME, username.c_str()); curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeStringListCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fileList); res = curl_easy_perform(curl); if(res != CURLE_OK) { fprintf(stderr, "Failed to get file list, error code :%d ,%s\n", res, curl_easy_strerror(res)); } else { // for(const std::string& filename : fileList) // { // printf("%s\n", filename.c_str()); // } result = true; } curl_easy_cleanup(curl); } if(hasInstace == false) { curl_global_cleanup(); } return result; } /* 创建文件夹 */ bool CurlFtp::createDir(const std::string &ftpUrl, const std::string &username, const std::string &password, const std::string &dirName) { CURL *curl; CURLcode res; bool result = false; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, ftpUrl.c_str()); curl_easy_setopt(curl, CURLOPT_USERNAME, username.c_str()); curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); // Create a list of FTP commands to be executed on the server struct curl_slist *headerlist = NULL; std::string mkdir = "MKD " + dirName; headerlist = curl_slist_append(headerlist, mkdir.c_str()); // Set the list of FTP commands to be executed on the server before the transfer curl_easy_setopt(curl, CURLOPT_QUOTE, headerlist); // Tell libcurl to not include the body in the output curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); res = curl_easy_perform(curl); if(res != CURLE_OK) { fprintf(stderr, "createDir() failed, error code :%d ,%s\n", res, curl_easy_strerror(res)); result = false; }else { result = true; } curl_easy_cleanup(curl); curl_slist_free_all(headerlist); } if(hasInstace == false) { curl_global_cleanup(); } return result; } /* 设置IP和端口 */ bool CurlFtp::setFtpIPAndPort(const std::string& IP, const std::string& port) { /*先判断是否有ftp器前缀,通过正则表达式,取出IP地址和端口号,去掉前缀和后面的'/ */ m_IP = IP; m_port = port; m_ftpUrl = "ftp://" + m_IP + ":" + m_port; printf("ftpUrl = %s\n", m_ftpUrl.c_str()); return true; } /* 设置用户名和密码 */ bool CurlFtp::setFtpUsernameAndPassword(const std::string& username, const std::string& password) { m_username = username; m_password = password; return true; } /* 列出文件列表 */ bool CurlFtp::listAll(std::string dir, std::vector& fileList) { if(m_IP.empty() || m_port.empty()) { printf("IP or port is empty\n"); return false; } if(m_curl == nullptr) { printf("m_curl is nullptr\n"); return false; } bool result = false; /* 先设置FTP地址 */ std::string ftpUrl = m_ftpUrl + dir; curl_easy_setopt(m_curl, CURLOPT_URL, ftpUrl.c_str()); /* 设置用户名和密码 */ curl_easy_setopt(m_curl, CURLOPT_USERNAME, m_username.c_str()); curl_easy_setopt(m_curl, CURLOPT_PASSWORD, m_password.c_str()); /* 设置列出文件命令,只列出文件名称,不携带信息 */ // curl_easy_setopt(m_curl, CURLOPT_DIRLISTONLY, 1L); /* 设置回调函数 */ curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeStringListCallback); /* 设置需要写入的容器 */ curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &fileList); /* 发送请求 */ m_res = curl_easy_perform(m_curl); if(m_res != CURLE_OK) { fprintf(stderr, "Failed to get file list, error code :%d ,%s\n", m_res, curl_easy_strerror(m_res)); result = false; } else { result = true; } // curl_easy_cleanup(m_curl); return result; }