Browse Source

V0.6.6
1、用列出文件夹列表的方式,判断SFTP文件夹是否存在

Apple 3 months ago
parent
commit
5afba7c6a7
2 changed files with 150 additions and 82 deletions
  1. 141 80
      common/CurlFtp/CurlFtp.cpp
  2. 9 2
      common/CurlFtp/CurlFtp.h

+ 141 - 80
common/CurlFtp/CurlFtp.cpp

@@ -339,6 +339,20 @@ static char* GBToUTF8(const char* gb2312)
 }
 #endif /* _WIN32 */
 
+
+/* 正则表达式,匹配多个空格 */
+const std::regex parseRegSpace(R"(( )+)");
+/* 匹配以非空格开头的字符,空格隔开,中间任意字符,空格隔开,非空格组成的结尾
+ * (文件类型) ... (文件大小,$5) ... (文件名)
+ */
+const std::regex parseReg1(R"(^([^ ]+) (\d*) (\w*) (\w*) (\d*) (.*) ([^ ]+)$)");
+// SPDLOG_INFO("\n-------------------\n");
+/* 匹配换行符,分割每一行 */
+const std::regex parseReg2(R"(\n)");
+/* 匹配文件夹 */
+const std::regex parseReg3(R"(^d.*)");
+/* 匹配文件 */
+const std::regex parseReg4(R"(^-.*$)");
 /**
  * @brief 解析字符串文件信息,如果FTP服务器规定好个编码,不需要进行转换
  * 
@@ -357,44 +371,44 @@ static bool parseFileInfo(const std::string& strSrc, std::vector<CF_FileInfo>& f
 #endif /* _WIN32 */
     
     // SPDLOG_DEBUG("\n{}", str2);
-    /* 正则表达式,匹配多个空格 */
-    std::regex reg(R"(( )+)");
-    /* 匹配以非空格开头的字符,空格隔开,中间任意字符,空格隔开,非空格组成的结尾
-     * (文件类型) ... (文件大小,$5) ... (文件名)
-     */
-    std::regex reg1(R"(^([^ ]+) (\d*) (\w*) (\w*) (\d*) (.*) ([^ ]+)$)");
-    // SPDLOG_INFO("\n-------------------\n");
-    /* 匹配换行符,分割每一行 */
-    std::regex reg2(R"(\n)");
-    /* 匹配文件夹 */
-    std::regex reg3(R"(^d.*)");
-    /* 匹配文件 */
-    std::regex reg4(R"(^-.*$)");
+    // /* 正则表达式,匹配多个空格 */
+    // std::regex regSpace(R"(( )+)");
+    // /* 匹配以非空格开头的字符,空格隔开,中间任意字符,空格隔开,非空格组成的结尾
+    //  * (文件类型) ... (文件大小,$5) ... (文件名)
+    //  */
+    // std::regex reg1(R"(^([^ ]+) (\d*) (\w*) (\w*) (\d*) (.*) ([^ ]+)$)");
+    // // SPDLOG_INFO("\n-------------------\n");
+    // /* 匹配换行符,分割每一行 */
+    // std::regex reg2(R"(\n)");
+    // /* 匹配文件夹 */
+    // std::regex reg3(R"(^d.*)");
+    // /* 匹配文件 */
+    // std::regex reg4(R"(^-.*$)");
 
     /* -1 表示对正则表达式之前的子序列感兴趣
      * 0 表示对正则表达式本身感兴趣,输出的就是换行符 */
-    std::sregex_token_iterator it2(str2.begin(), str2.end(), reg2, -1);
+    std::sregex_token_iterator it2(str2.begin(), str2.end(), parseReg2, -1);
     /* 这里取出每一行 */
     for(; it2 != std::sregex_token_iterator(); ++it2)
     {
         /* 去掉多余的空格 */
-        auto line = std::regex_replace(it2->str(), reg, " ");
+        auto line = std::regex_replace(it2->str(), parseRegSpace, " ");
         // SPDLOG_INFO("{}", line);
         CF_FileInfo fi;
         /* 取出文件类型 */
-        std::string strFileType = std::regex_replace(line, reg1, "$1");
-        if(std::regex_match(strFileType, reg3))
+        std::string strFileType = std::regex_replace(line, parseReg1, "$1");
+        if(std::regex_match(strFileType, parseReg3))
         {
             fi.type = CF_FileType::DIR;
-        }else if (std::regex_match(strFileType, reg4))
+        }else if (std::regex_match(strFileType, parseReg4))
         {
             fi.type = CF_FileType::FILE;
         }
         /* 取出文件大小 */
-        std::string strFileSize = std::regex_replace(line, reg1, "$5");
+        std::string strFileSize = std::regex_replace(line, parseReg1, "$5");
         fi.size = std::stoull(strFileSize);
         /* 取出文件名 */
-        std::string strFileName = std::regex_replace(line, reg1, "$7");
+        std::string strFileName = std::regex_replace(line, parseReg1, "$7");
         fi.name = strFileName;
         /* 加入队列 */
         fileInfo.push_back(fi);
@@ -554,63 +568,34 @@ bool CurlFtp::getDirList(std::string dir, std::vector<std::string>& dirList)
 }
 
 
-/* 判断文件夹是否存在 */
+/**
+ * @brief 判断文件夹是否存在,FTP和SFTP判断方式不同
+ *        FTP使用curl检测判断,但是SFTP无论文件夹是否存在都会返回真,所以只能通过列出文件夹的方式判断
+ * 
+ * @param dir 
+ * @return true 
+ * @return false 
+ */
 bool CurlFtp::isDirExist(const std::string& dir)
 {
-    SPDLOG_DEBUG("Check dir: {}", dir);
+    SPDLOG_DEBUG("Check remote dir: {}", dir);
     if(m_ftpUrl.empty())
     {
         SPDLOG_ERROR("ftpUrl is empty");
         return false;
     }
-    /* 检查传入的文件夹 */
-    auto dirTmp = checkDirPath(dir);
-
-    // CURL* curl = nullptr;
-    resetCurl(m_curl);
-    std::string ftpUrl = m_ftpUrl + dirTmp;
-    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_NOBODY, 1L);
-    curl_easy_setopt(m_curl, CURLOPT_HEADER, 1L);
-
-    /* 设置SFTP */
-    setSftp(m_curl);
-    /* 启用调试信息 */
-    if(m_enableCurlDebug)
-    {
-        curl_easy_setopt(m_curl, CURLOPT_VERBOSE, 1L);
-    }
-
-    /* 启用持久连接 */
-    // curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPALIVE, 1L);
-    /* 这里只需要执行一次 */
-    CURLcode res = curl_easy_perform(m_curl);
-    bool result = true;
-    if(res == CURLE_REMOTE_FILE_NOT_FOUND)
+    if(dir == "/")
     {
-        result = false;
-    }
-    else if(res != CURLE_OK)
-    {
-        // SPDLOG_ERROR("Check remote dir error, error code: {} ,{}", (int)res, curl_easy_strerror(res));
-        result = false;
+        return true;
     }
-    else 
+    bool result = false;
+    if(m_isSftp)
     {
-        /* sftp即使远程文件夹不存在也会返回OK,这里使用http进行检查 */
-        // long response_code = -1;
-        // res = curl_easy_getinfo(m_curl, CURLINFO_HTTP_CONNECTCODE, &response_code);
-        // if((res == CURLE_OK) && (response_code == 0))
-        // {
-        //     SPDLOG_ERROR("Remote directory not found: {}", dir);
-        //     result = false;
-        // }
-        // SPDLOG_DEBUG("response_code: {}", response_code);
+        result = checkSftpDirExist(dir);
+    }else {
+        result = checkFtpDirExist(dir);
     }
-
+    
     return result;
 }
 
@@ -644,24 +629,20 @@ bool CurlFtp::createDirectory(const std::string& ftpDir)
     //     SPDLOG_ERROR("Create FTP DIR, curl init failed !");
     //     return false;
     // }
-    if(m_curl == nullptr)
-    {
-        m_curl = curl_easy_init();
-        if(m_curl == nullptr)
-        {
-            SPDLOG_ERROR("curl init failed !");
-            return false;
-        }
-    }else {
-        curl_easy_reset(m_curl);
-    }
+    resetCurl(m_curl);
 
     curl_easy_setopt(m_curl, CURLOPT_URL, m_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());
     /* 创建FTP头信息 */
     struct curl_slist *headerlist = NULL;
-    std::string mkdir = "MKD " + dirTmp;
+    std::string mkdir;
+    if(m_isSftp)
+    {
+        mkdir = "MKDIR " + dirTmp;
+    }else {
+        mkdir = "MKD " + dirTmp;
+    }
     headerlist = curl_slist_append(headerlist, mkdir.c_str());
     /* 设置FTP命令行选项 */
     curl_easy_setopt(m_curl, CURLOPT_QUOTE, headerlist);
@@ -684,12 +665,12 @@ bool CurlFtp::createDirectory(const std::string& ftpDir)
     // 启用持久连接
     // curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPALIVE, 1L);
 
-    SPDLOG_DEBUG("Create dir: {}", dirTmp);
+    SPDLOG_DEBUG("Create remote dir: {}", dirTmp);
     // CURLcode res = curl_easy_perform(curl);
     bool ret = performCurl(m_curl);
     if(!ret)
     {
-        SPDLOG_ERROR("Failed to create FTP Dir");
+        SPDLOG_ERROR("Failed to create remote Dir");
     }
 
     // curl_easy_cleanup(curl);
@@ -1336,5 +1317,85 @@ bool CurlFtp::setSftp(CURL* curl)
     return true;
 }
 
+/* 检查FTP文件夹是否存在 */
+bool CurlFtp::checkFtpDirExist(const std::string& dir)
+{
+    /* 检查传入的文件夹 */
+    auto dirTmp = checkDirPath(dir);
+    resetCurl(m_curl);
+    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_NOBODY, 1L);
+    curl_easy_setopt(m_curl, CURLOPT_HEADER, 1L);
+
+    /* 设置SFTP */
+    setSftp(m_curl);
+    /* 启用调试信息 */
+    if(m_enableCurlDebug)
+    {
+        curl_easy_setopt(m_curl, CURLOPT_VERBOSE, 1L);
+    }
+
+    /* 启用持久连接 */
+    // curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPALIVE, 1L);
+    /* 这里只需要执行一次 */
+    CURLcode res = curl_easy_perform(m_curl);
+    bool result = true;
+    if(res == CURLE_REMOTE_FILE_NOT_FOUND)
+    {
+        result = false;
+    }
+    else if(res != CURLE_OK)
+    {
+        // SPDLOG_ERROR("Check remote dir error, error code: {} ,{}", (int)res, curl_easy_strerror(res));
+        result = false;
+    }
+    else 
+    {
+        /* sftp即使远程文件夹不存在也会返回OK,这里使用http进行检查 */
+        // long response_code = -1;
+        // res = curl_easy_getinfo(m_curl, CURLINFO_HTTP_CONNECTCODE, &response_code);
+        // if((res == CURLE_OK) && (response_code == 0))
+        // {
+        //     SPDLOG_ERROR("Remote directory not found: {}", dir);
+        //     result = false;
+        // }
+        // SPDLOG_DEBUG("response_code: {}", response_code);
+    }
+    return result;
+}
+
+/* 检查SFTP文件夹是否存在,这里通过列出上一层的文件夹中的内容,然后进行对比判断的 */
+bool CurlFtp::checkSftpDirExist(const std::string& dir)
+{
+    /* 取出上一层文件夹路径 */
+    std::string parentDir = std::filesystem::path(dir).parent_path().string();
+    // SPDLOG_DEBUG("Parent dir: {}", parentDir);
+    std::vector<std::string> vecDir;
+    bool ret = getDirList(parentDir, vecDir);
+    if(!ret)
+    {
+        SPDLOG_ERROR("Failed to check sftp dir: {}", dir);
+        return false;
+    }
+    /* 取出本层文件夹名称 */
+    std::string dirName = std::filesystem::path(dir).filename().string();
+    // SPDLOG_DEBUG("Dir name: {}", dirName);
+    /* 判断是否存在 */
+    bool result = false;
+    for(const std::string& str : vecDir)
+    {
+        if(str == dirName)
+        {
+            result = true;
+            break;
+        }
+    }
+    return result;
+}
+
 
 

+ 9 - 2
common/CurlFtp/CurlFtp.h

@@ -13,9 +13,12 @@
  * 使用CURL进行FTP操作,这里是单线程的,需要多线程同时操作,就创建多个实例
  *
  *     1.默认超时时间是30s
- *     2.默认端口是21
- *     3.设置好IP和端口号后,后续输入的文件路径都是想对你路径,无需添加IP和端口号
+ *     2.FTP默认端口是21,SFTP默认端口是22
+ *     3.设置好IP和端口号后,后续输入的文件路径都是相对路径,无需添加IP和端口号
  *     4.使用ftp,用setFtpIPAndPort()设置IP和端口,使用sftp,用setSftpIPAndPort()设置IP和端口
+ *     5.这里使用了filesystem,需要C++17支持,uos默认的gcc版本是8.3,支持C++17,但是需要手动开启
+ *       这个库的支持,在项目文件里添加“stdc++fs”这个库,如下:
+ *          target_link_libraries(${this_exe} PRIVATE stdc++fs)
  */
 
 
@@ -75,6 +78,10 @@ private:
     inline bool resetCurl(CURL* curl);
     /* 设置sftp,如果是sftp就设置 */
     inline bool setSftp(CURL* curl);
+    /* 检查FTP文件夹是否存在 */
+    bool checkFtpDirExist(const std::string& dir);
+    /* 检查SFTP文件夹是否存在 */
+    bool checkSftpDirExist(const std::string& dir);
 
 private:
     std::mutex m_mutexCurl;                 /* curl互斥锁 */