|
@@ -5,7 +5,6 @@
|
|
|
#include <iosfwd>
|
|
|
|
|
|
#include "fmtlog.h"
|
|
|
-#include "CurlFtpInfo.h"
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
@@ -70,6 +69,23 @@ static int writeStringListCallback(void* buffer, size_t size, size_t nmemb, void
|
|
|
return size * nmemb;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief 写入文件回调函数
|
|
|
+ *
|
|
|
+ * @param contents 下载到的数据内容
|
|
|
+ * @param size 数据大小
|
|
|
+ * @param nmemb 数据单位
|
|
|
+ * @param pFile 文件指针
|
|
|
+ * @return size_t 写入的大小
|
|
|
+ */
|
|
|
+static size_t writeDataCallBack(void* contents, size_t size, size_t nmemb, FILE* pFile)
|
|
|
+{
|
|
|
+ size_t written = fwrite(contents, size, nmemb, pFile);
|
|
|
+ return written;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
/* 使用Windows API进行编码转换 */
|
|
|
#if defined(_WIN32)
|
|
|
static char* GBToUTF8(const char* gb2312)
|
|
@@ -90,8 +106,8 @@ static char* GBToUTF8(const char* gb2312)
|
|
|
/**
|
|
|
* @brief 解析字符串文件信息
|
|
|
*
|
|
|
- * @param strSrc
|
|
|
- * @param fileList
|
|
|
+ * @param strSrc 读取到的字符串
|
|
|
+ * @param fileList 文件信息列表
|
|
|
* @return true
|
|
|
* @return false
|
|
|
*/
|
|
@@ -162,7 +178,6 @@ CurlFtp::CurlFtp()
|
|
|
/* 调用初始化函数,这个函数可以重复调用 */
|
|
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
|
|
/* 初始化curl */
|
|
|
- m_curl = curl_easy_init();
|
|
|
hasInstace = true;
|
|
|
}
|
|
|
|
|
@@ -170,68 +185,10 @@ CurlFtp::CurlFtp()
|
|
|
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文件夹
|
|
@@ -379,13 +336,13 @@ bool CurlFtp::createDir(const std::string &ftpUrl, const std::string &username,
|
|
|
|
|
|
|
|
|
/* 设置IP和端口 */
|
|
|
-bool CurlFtp::setFtpIPAndPort(const std::string& IP, const std::string& port)
|
|
|
+bool CurlFtp::setFtpIPAndPort(const std::string& IP, const int port)
|
|
|
{
|
|
|
/*先判断是否有ftp器前缀,通过正则表达式,取出IP地址和端口号,去掉前缀和后面的'/ */
|
|
|
m_IP = IP;
|
|
|
m_port = port;
|
|
|
- m_ftpUrl = "ftp://" + m_IP + ":" + m_port;
|
|
|
- printf("ftpUrl = %s\n", m_ftpUrl.c_str());
|
|
|
+ m_ftpUrl = "ftp://" + m_IP + ":" + std::to_string(m_port);
|
|
|
+ FMTLOG_INFO("ftpUrl = {}", m_ftpUrl);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
@@ -404,68 +361,240 @@ bool CurlFtp::setFtpUsernameAndPassword(const std::string& username, const std::
|
|
|
/* 列出文件列表 */
|
|
|
bool CurlFtp::getFileList(std::string dir, std::vector<std::string>& fileList)
|
|
|
{
|
|
|
- if(m_IP.empty() || m_port.empty())
|
|
|
+ if(m_IP.empty())
|
|
|
{
|
|
|
FMTLOG_WARN("IP or port is empty");
|
|
|
return false;
|
|
|
}
|
|
|
- if(m_curl == nullptr)
|
|
|
+ /* 检查dir,添加前缀“/” */
|
|
|
+ auto dirTmp = checkDirPath(dir);
|
|
|
+
|
|
|
+ CURL *curl = nullptr;
|
|
|
+ curl = curl_easy_init();
|
|
|
+ if(curl == nullptr)
|
|
|
{
|
|
|
- FMTLOG_WARN("m_curl is nullptr");
|
|
|
+ FMTLOG_ERROR("curl init failed !");
|
|
|
return false;
|
|
|
}
|
|
|
+
|
|
|
std::vector<CF_FileInfo> listInfo;
|
|
|
- listAll(dir, listInfo);
|
|
|
- // for(const CF_FileInfo& fi : listInfo)
|
|
|
- // {
|
|
|
- // FMTLOG_INFO("type = {}, size = {}, name = {}", (int)fi.type, fi.size, fi.name);
|
|
|
- // }
|
|
|
+ /* 获取文件信息 */
|
|
|
+ listAll(curl, dirTmp, listInfo);
|
|
|
+ for(const CF_FileInfo& fi : listInfo)
|
|
|
+ {
|
|
|
+ // FMTLOG_INFO("type = {}, size = {}, name = {}", (int)fi.type, fi.size, fi.name);
|
|
|
+ if(fi.type == CF_FileType::FILE)
|
|
|
+ {
|
|
|
+ fileList.push_back(fi.name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ curl_easy_cleanup(curl);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+/* 获取文件夹列表 */
|
|
|
+bool CurlFtp::getDirList(std::string dir, std::vector<std::string>& dirList)
|
|
|
+{
|
|
|
+ if(m_IP.empty())
|
|
|
+ {
|
|
|
+ FMTLOG_WARN("IP or port is empty");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /* 检查dir,添加前缀“/” */
|
|
|
+ auto dirTmp = checkDirPath(dir);
|
|
|
+
|
|
|
+ CURL *curl = nullptr;
|
|
|
+ curl = curl_easy_init();
|
|
|
+ if(curl == nullptr)
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("curl init failed !");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<CF_FileInfo> listInfo;
|
|
|
+ /* 获取文件信息 */
|
|
|
+ listAll(curl, dirTmp, listInfo);
|
|
|
+ for(const CF_FileInfo& fi : listInfo)
|
|
|
+ {
|
|
|
+ // FMTLOG_INFO("type = {}, size = {}, name = {}", (int)fi.type, fi.size, fi.name);
|
|
|
+ if(fi.type == CF_FileType::DIR)
|
|
|
+ {
|
|
|
+ dirList.push_back(fi.name);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ curl_easy_cleanup(curl);
|
|
|
|
|
|
-/* 列出文件列表 */
|
|
|
-bool CurlFtp::listAll(std::string dir, std::vector<CF_FileInfo>& fileList)
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* 判断文件夹是否存在 */
|
|
|
+bool CurlFtp::isDirExist(const std::string& dir)
|
|
|
{
|
|
|
- if(m_IP.empty() || m_port.empty())
|
|
|
+ if(m_ftpUrl.empty())
|
|
|
{
|
|
|
- printf("IP or port is empty\n");
|
|
|
+ FMTLOG_ERROR("ftpUrl is empty");
|
|
|
return false;
|
|
|
}
|
|
|
- if(m_curl == nullptr)
|
|
|
+ /* 检查传入的文件夹 */
|
|
|
+ auto dirTmp = checkDirPath(dir);
|
|
|
+
|
|
|
+ CURL* curl = nullptr;
|
|
|
+ curl = curl_easy_init();
|
|
|
+ if(curl == nullptr)
|
|
|
{
|
|
|
- printf("m_curl is nullptr\n");
|
|
|
+ FMTLOG_ERROR("curl init failed !");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ std::string ftpUrl = m_ftpUrl + dirTmp;
|
|
|
+ curl_easy_setopt(curl, CURLOPT_URL, ftpUrl.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_NOBODY, 1L);
|
|
|
+
|
|
|
+ CURLcode res = curl_easy_perform(curl);
|
|
|
+ bool result = true;
|
|
|
+ if(res != CURLE_OK)
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("Failed to get file list, error code: {} ,{}", (int)res, curl_easy_strerror(res));
|
|
|
+ result = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+/* 下载文件 */
|
|
|
+bool CurlFtp::downloadFile(const std::string& remoteFile, const std::string& localFile)
|
|
|
+{
|
|
|
+ if(m_ftpUrl.empty())
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("ftpUrl is empty");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ CURL* curl = nullptr;
|
|
|
+ curl = curl_easy_init();
|
|
|
+ if(curl == nullptr)
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("curl init failed !");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /* 检查传入的文件是否符合规范 */
|
|
|
+ std::string ftpUrl = m_ftpUrl + remoteFile;
|
|
|
+
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief 列出文件列表,这个需要的参数很多,无法设置成静态函数
|
|
|
+ *
|
|
|
+ * @param curl CURL句柄
|
|
|
+ * @param dir 文件夹,相对路径,不带有IP和端口号
|
|
|
+ * @param fileList 返回值,文件列表
|
|
|
+ * @return true
|
|
|
+ * @return false
|
|
|
+ */
|
|
|
+bool CurlFtp::listAll(CURL* curl, std::string dir, std::vector<CF_FileInfo>& fileInfoList)
|
|
|
+{
|
|
|
+ if(m_IP.empty())
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("IP is empty");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(curl == nullptr)
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("curl is nullptr");
|
|
|
return false;
|
|
|
}
|
|
|
bool result = false;
|
|
|
std::string strSrc;
|
|
|
/* 先设置FTP地址 */
|
|
|
std::string ftpUrl = m_ftpUrl + dir;
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_URL, ftpUrl.c_str());
|
|
|
+ curl_easy_setopt(curl, CURLOPT_URL, ftpUrl.c_str());
|
|
|
+ curl_easy_setopt(curl, CURLOPT_PORT, m_port);
|
|
|
/* 设置用户名和密码 */
|
|
|
- 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(curl, CURLOPT_USERNAME, m_username.c_str());
|
|
|
+ curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
|
|
|
|
|
|
/* 设置列出文件命令,只列出文件名称,不携带信息 */
|
|
|
// curl_easy_setopt(m_curl, CURLOPT_DIRLISTONLY, 1L);
|
|
|
/* 设置回调函数 */
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeStringCallback);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeStringCallback);
|
|
|
/* 设置需要写入的容器,回调函数的第四个参数 */
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &strSrc);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &strSrc);
|
|
|
+
|
|
|
+ /* 设置超时时间 */
|
|
|
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
|
|
|
|
|
|
/* 发送请求 */
|
|
|
- m_res = curl_easy_perform(m_curl);
|
|
|
- if(m_res != CURLE_OK)
|
|
|
+ CURLcode res = curl_easy_perform(curl);
|
|
|
+ if(res != CURLE_OK)
|
|
|
{
|
|
|
- FMTLOG_ERROR("Failed to get file list, error code: {} ,{}", (int)m_res, curl_easy_strerror(m_res));
|
|
|
+ FMTLOG_ERROR("Failed to get file list, error code: {} ,{}", (int)res, curl_easy_strerror(res));
|
|
|
+ FMTLOG_ERROR("ftpUrl = {}", ftpUrl);
|
|
|
return false;
|
|
|
}
|
|
|
/* 解析字符串 */
|
|
|
- parseFileInfo(strSrc, fileList);
|
|
|
+ parseFileInfo(strSrc, fileInfoList);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+/* 检查文件夹路径是否合规,不合规就修改 */
|
|
|
+std::string CurlFtp::checkDirPath(const std::string& dir)
|
|
|
+{
|
|
|
+ std::string dirTmp = dir;
|
|
|
+ /* 检查是否以“/”开头 */
|
|
|
+ std::regex reg(R"(^/[.]*)");
|
|
|
+ if(!std::regex_match(dirTmp, reg))
|
|
|
+ {
|
|
|
+ dirTmp = "/" + dirTmp;
|
|
|
+ }
|
|
|
+ /* 如果有重复的“/”,替换成一个 “/” */
|
|
|
+ std::regex reg1(R"(//)");
|
|
|
+ dirTmp = std::regex_replace(dirTmp, reg1, "/");
|
|
|
+ /* 检查是否以“/”结束 */
|
|
|
+ std::regex reg2(R"([.]*/$)");
|
|
|
+ if(!std::regex_match(dirTmp, reg2))
|
|
|
+ {
|
|
|
+ dirTmp = dirTmp + "/";
|
|
|
+ }
|
|
|
+
|
|
|
+ return dirTmp;
|
|
|
+}
|
|
|
+
|
|
|
+/* 检查文件路径是否合规 */
|
|
|
+std::string CurlFtp::checkFilePath(const std::string& file)
|
|
|
+{
|
|
|
+ std::string dirTmp = file;
|
|
|
+ /* 检查是否以“/”结束,如果是以“/”结尾,返回空字符串,并报错 */
|
|
|
+ std::regex reg2(R"([.]*/$)");
|
|
|
+ if(std::regex_match(dirTmp, reg2))
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("File path is not correct, end with '/'");
|
|
|
+ return std::string();
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 检查是否以“/”开头 */
|
|
|
+ std::regex reg(R"(^/[.]*)");
|
|
|
+ if(!std::regex_match(dirTmp, reg))
|
|
|
+ {
|
|
|
+ dirTmp = "/" + dirTmp;
|
|
|
+ }
|
|
|
+ /* 如果有重复的“/”,替换成一个 “/” */
|
|
|
+ std::regex reg1(R"(//)");
|
|
|
+ dirTmp = std::regex_replace(dirTmp, reg1, "/");
|
|
|
+
|
|
|
+
|
|
|
+ return dirTmp;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|