Browse Source

V0.2.13
1、完善了CurlFtp类
2、可以列出文件列表和文件夹列表
3、可以检测文件夹是否存在

Apple 6 months ago
parent
commit
6babece65d

+ 217 - 88
common/CurlFtp/CurlFtp.cpp

@@ -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;
+}
+
+
+
 

+ 29 - 14
common/CurlFtp/CurlFtp.h

@@ -6,7 +6,18 @@
 #include <vector>
 #include <mutex>
 
-struct CF_FileInfo;
+#include "CurlFtpInfo.h"
+
+
+/**
+ * 使用CURL进行FTP操作,这个类有两种方式,一种是直接使用静态方法,另一种是创建实例
+ * 使用静态函数可以进行一些简单的操作,但是如果需要进行多次操作,最好创建实例
+ *
+ *     1.默认超时时间是10s
+ *     2.默认端口是21
+ * 
+ */
+
 
 class CurlFtp
 {
@@ -17,38 +28,42 @@ public:
     static std::string listDir(const std::string &ftpUrl, const std::string &username, const std::string &password);
     /* 列出文件夹中的所有文件 */
     static bool listFiles(const std::string &ftpUrl, const std::string &username, const std::string &password, std::vector<std::string>& fileList);
-    /* 检查文件夹是否存在 */
-    // static bool isDirExists(const std::string &ftpUrl, const std::string &username, const std::string &password);
-    /* 使用正则表达式提取出文件夹 */
-    // static bool CurlFtp::extractDirectories(const std::string& responseString);
-
     /* 创建文件夹 */
     static bool createDir(const std::string &ftpUrl, const std::string &username, const std::string &password, const std::string &dirName);
 
+    /*********************** 成员函数 *********************/
     /* 设置IP和端口 */
-    bool setFtpIPAndPort(const std::string& IP, const std::string& port);
+    bool setFtpIPAndPort(const std::string& IP, const int port);
     /* 设置用户名和密码 */
     bool setFtpUsernameAndPassword(const std::string& username, const std::string& password);
     /* 列出文件列表 */
     bool getFileList(std::string dir, std::vector<std::string>& fileList);
+    /* 获取文件夹列表 */
+    bool getDirList(std::string dir, std::vector<std::string>& dirList);
+    /* 判断文件夹是否存在 */
+    bool isDirExist(const std::string& dir);
+
+    /* 下载文件 */
+    bool downloadFile(const std::string& remoteFile, const std::string& localFile);
 
 private:
     /* 列出所有内容 */
-    bool listAll(std::string dir, std::vector<CF_FileInfo>& fileList);
+    bool listAll(CURL* curl, std::string dir, std::vector<CF_FileInfo>& fileInfoList);
+    /* 检查文件夹路径是否合规,不合规就修改 */
+    std::string checkDirPath(const std::string& dir);
+    /* 检查文件路径是否合规 */
+    std::string checkFilePath(const std::string& file);
 
 private:
     std::mutex m_mutexCurl;                 /* curl互斥锁 */
-    CURL* m_curl = nullptr;                 /* curl句柄 */
-    CURLcode m_res = CURLE_OK;              /* 返回值 */
-    std::string m_responseString;           /*  */
+    std::string m_currentDir;               /* 当前目录 */
 
     std::string m_IP;                       /* IP */
-    std::string m_port;                     /* 端口 */
+    int m_port = 21;                        /* 端口 */
     std::string m_ftpUrl;                   /* ftpUrl */
+
     std::string m_username;
     std::string m_password;
-    std::string m_dirName;
-
 };
 
 

+ 2 - 2
common/CurlFtp/CurlFtpInfo.h

@@ -27,8 +27,8 @@ struct CF_FileInfo
 
     CF_FileInfo() : type(CF_FileType::UNKNOWN), size(0), name(""){}
     CF_FileInfo(CF_FileType type, uint64_t size, const std::string& name)
-        : type(type), size(size), name(name)
-    {}
+        : type(type), size(size), name(name) {}
+    
     CF_FileInfo& operator=(const CF_FileInfo& info)
     {
         type = info.type;

+ 2 - 2
common/CurlHttp/CurlHttp.cpp

@@ -49,13 +49,13 @@ static size_t WriteStringCallback(void* contents, size_t size, size_t nmemb, std
 
 CurlHttp::CurlHttp()
 {
-
+    curl_global_init(CURL_GLOBAL_DEFAULT);
 }
 
 
 CurlHttp::~CurlHttp()
 {
-
+    curl_global_cleanup();
 }
 
 /**

+ 5 - 4
common/FmtLog/fmtlog.h

@@ -28,7 +28,7 @@ const std::regex _reg_file(R"(.*/([\S]*[\.][\S]*)$)");
         std::string _log_file_src = __FILE__; \
         auto _log_file = std::regex_replace(_log_file_src, _reg_file, "$1"); \
         std::string _log_str = fmt::format(__VA_ARGS__); \
-        fmt::print(fg(fmt::color::blue), "[{}][{}:{}] {}\n",_log_time,_log_file ,__LINE__ ,_log_str); \
+        fmt::print(fg(fmt::color::blue), "[{}][{}][{}:{}] {}\n", _log_time, "DEBUG", _log_file , __LINE__ , _log_str); \
     }while(0)
 
 /* 正常输出 */
@@ -40,7 +40,7 @@ const std::regex _reg_file(R"(.*/([\S]*[\.][\S]*)$)");
         std::string _log_file_src = __FILE__; \
         auto _log_file = std::regex_replace(_log_file_src, _reg_file, "$1"); \
         std::string _log_str = fmt::format(__VA_ARGS__); \
-        fmt::print(fg(fmt::color::green), "[{}][{}:{}] {}\n",_log_time,_log_file ,__LINE__ ,_log_str); \
+        fmt::print(fg(fmt::color::green), "[{}][{}][{}:{}] {}\n", _log_time, "INFO", _log_file, __LINE__, _log_str); \
     }while(0)
 
 /* Warn输出 */
@@ -52,7 +52,7 @@ const std::regex _reg_file(R"(.*/([\S]*[\.][\S]*)$)");
         std::string _log_file_src = __FILE__; \
         auto _log_file = std::regex_replace(_log_file_src, _reg_file, "$1"); \
         std::string _log_str = fmt::format(__VA_ARGS__); \
-        fmt::print(fg(fmt::color::yellow), "[{}][{}:{}] {}\n",_log_time,_log_file ,__LINE__ ,_log_str); \
+        fmt::print(fg(fmt::color::yellow), "[{}][{}][{}:{}] {}\n", _log_time, "WARN", _log_file, __LINE__, _log_str); \
     }while(0)
 
 /* 错误输出 */
@@ -64,7 +64,7 @@ const std::regex _reg_file(R"(.*/([\S]*[\.][\S]*)$)");
         std::string _log_file_src = __FILE__; \
         auto _log_file = std::regex_replace(_log_file_src, _reg_file, "$1"); \
         std::string _log_str = fmt::format(__VA_ARGS__); \
-        fmt::print(fg(fmt::color::red), "[{}][{}:{}] {}\n",_log_time,_log_file ,__LINE__ ,_log_str); \
+        fmt::print(fg(fmt::color::red), "[{}][{}][{}:{}] {}\n", _log_time, "ERROR", _log_file, __LINE__, _log_str); \
     }while(0)
 
 // void hello()
@@ -74,6 +74,7 @@ const std::regex _reg_file(R"(.*/([\S]*[\.][\S]*)$)");
 //     std::string _log_time = fmt::format("{:%Y-%m-%d %H:%M:%S}", fmt::localtime(now_c));
 //     fmt::print(fg(fmt::color::green), "Hello, {}!\n", _log_time);
 //     std::regex_replace("hello", _reg_file, "$1");
+//     fmt::format(fg(fmt::color::green), "Hello, {}!\n", _log_time);
 // }
 
 #endif /* FMTLOG_H */