|
@@ -73,23 +73,37 @@ static int writeStringListCallback(void* buffer, size_t size, size_t nmemb, void
|
|
|
/**
|
|
|
* @brief 写入文件回调函数
|
|
|
*
|
|
|
- * @param contents 下载到的数据内容
|
|
|
+ * @param contents 读取到的数据内容
|
|
|
* @param size 数据大小
|
|
|
* @param nmemb 数据单位
|
|
|
* @param pFile 文件指针
|
|
|
- * @return size_t 写入的大小
|
|
|
+ * @return size_t 实际读取的大小
|
|
|
*/
|
|
|
static size_t writeDataCallBack(void* contents, size_t size, size_t nmemb, std::ostream* pFile)
|
|
|
{
|
|
|
pFile->write(reinterpret_cast<char*>(contents), size * nmemb);
|
|
|
- // if(pFile->fail())
|
|
|
- // {
|
|
|
- // FMTLOG_ERROR("Failed to write data to file");
|
|
|
- // return 0;
|
|
|
- // }
|
|
|
return size * nmemb;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @brief 读取文件回调函数
|
|
|
+ *
|
|
|
+ * @param contents 下载到的数据内容
|
|
|
+ * @param size 数据大小
|
|
|
+ * @param nmemb 数据单位
|
|
|
+ * @param pFile 文件指针
|
|
|
+ * @return size_t 写入的大小
|
|
|
+ */
|
|
|
+static size_t readDataCallBack(void* contents, size_t size, size_t nmemb, std::istream* pFile)
|
|
|
+{
|
|
|
+ pFile->read(reinterpret_cast<char*>(contents), size * nmemb);
|
|
|
+ /* 获取读取到的字节数,可能读取到文件末尾,所以不能直接使用传入的字节数 */
|
|
|
+ size_t readSize = pFile->gcount();
|
|
|
+
|
|
|
+ return readSize;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* @brief 上传和下载进度回调函数,这个函数kennel会被多次调用,即使是没有在下载的时候,因此需要判断传入的数据是否是0
|
|
|
* 必须将 CURLOPT_NOPROGRESS 设为 0 才能真正调用该函数。
|
|
@@ -119,13 +133,13 @@ static int progress_callback(void *clientp,
|
|
|
/* 计算进度,百分比 */
|
|
|
double downloadPercent = (double)dlnow / (double)dltotal * 100;
|
|
|
/* 使用回车刷新这一行 */
|
|
|
- FMTLOG_DEBUG_NON("Download Total / now : {} / {}, {:.1f}%\r", dltotal, dlnow, downloadPercent);
|
|
|
+ FMTLOG_DEBUG_NON("Download Total / now : {} / {}, {:.2f}%\r", dltotal, dlnow, downloadPercent);
|
|
|
}
|
|
|
/* 正在上传 */
|
|
|
else if(ultotal > 0)
|
|
|
{
|
|
|
double uploadPercent = (double)ulnow / (double)ultotal * 100;
|
|
|
- FMTLOG_DEBUG_NON("Upload Total / now : {} / {}, {:.1f}%\r", ultotal, ulnow, uploadPercent);
|
|
|
+ FMTLOG_DEBUG_NON("Upload Total / now : {} / {}, {:.2f}%\r", ultotal, ulnow, uploadPercent);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -703,8 +717,95 @@ bool CurlFtp::downloadFile(const std::string& remoteFile, const std::string& loc
|
|
|
*/
|
|
|
bool CurlFtp::uploadFile(const std::string& localFile, const std::string& remoteFile)
|
|
|
{
|
|
|
+ if(m_ftpUrl.empty())
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("ftpUrl is empty");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /* 检查本地文件是否存在 */
|
|
|
+ if(!std::filesystem::exists(localFile))
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("Local file is not exist: {}", localFile);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /* 检查FTP文件名是否符合规范 */
|
|
|
+ std::string remoteFileTmp = checkFilePath(remoteFile);
|
|
|
+ std::string remoteDirTmp = remoteFileTmp.substr(0, remoteFileTmp.find_last_of("/"));
|
|
|
+ /* 检查远程FTP上的文件夹是否存在,不存在则创建 */
|
|
|
+ if(!isDirExist(remoteDirTmp))
|
|
|
+ {
|
|
|
+ if(!createDirectories(remoteDirTmp))
|
|
|
+ {
|
|
|
+ // FMTLOG_ERROR("Failed to create remote dir: {}", remoteFileTmp);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 拼接远程文件的url */
|
|
|
+ std::string ftpUrl = m_ftpUrl + remoteFileTmp;
|
|
|
+
|
|
|
+ /* 打开文件 */
|
|
|
+ std::ifstream ifs;
|
|
|
+ ifs.open(localFile, std::ios::in | std::ios::binary);
|
|
|
+ if(!ifs.is_open())
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("Failed to open local file: {}", localFile);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /* 获取文件大小 */
|
|
|
+ // auto startPos = ifs.tellg();
|
|
|
+ ifs.seekg(0, std::ios::end);
|
|
|
+ auto fileSize = ifs.tellg();
|
|
|
+ /* 恢复指针到文件头 */
|
|
|
+ ifs.seekg(0, std::ios::beg);
|
|
|
+ FMTLOG_DEBUG("File size: {}", (long)fileSize);
|
|
|
|
|
|
- return true;
|
|
|
+ CURL* curl = nullptr;
|
|
|
+ curl = curl_easy_init();
|
|
|
+ if(curl == nullptr)
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("curl init failed !");
|
|
|
+ ifs.close();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /* 设置FTP地址 */
|
|
|
+ curl_easy_setopt(curl, CURLOPT_URL, ftpUrl.c_str());
|
|
|
+ curl_easy_setopt(curl, CURLOPT_PORT, m_port);
|
|
|
+ /* 设置用户名和密码 */
|
|
|
+ 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_FOLLOWLOCATION, 1L);
|
|
|
+ /* 启用上传 */
|
|
|
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
|
|
+ /* 设置回调函数 */
|
|
|
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, readDataCallBack);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_READDATA, &ifs);
|
|
|
+ /* 设置上传文件的大小 */
|
|
|
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
|
|
|
+ /* 设置超时时间 */
|
|
|
+ // curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30L);
|
|
|
+ /* 设置进度回调函数 */
|
|
|
+ curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
|
|
|
+ curl_easy_setopt(curl, CURLOPT_XFERINFODATA, nullptr);
|
|
|
+ /* 启用下载进度回调函数 */
|
|
|
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
|
|
+ /* 发送请求 */
|
|
|
+ CURLcode res = curl_easy_perform(curl);
|
|
|
+ bool result = true;
|
|
|
+ if(res != CURLE_OK)
|
|
|
+ {
|
|
|
+ FMTLOG_ERROR("Upload file failed, error code: {} ,{}", (int)res, curl_easy_strerror(res));
|
|
|
+ FMTLOG_ERROR("ftpUrl = {}", ftpUrl);
|
|
|
+ result = false;
|
|
|
+ }
|
|
|
+ /* 关闭文件,清理curl */
|
|
|
+ ifs.close();
|
|
|
+ curl_easy_cleanup(curl);
|
|
|
+ /* 打印一个换行符 */
|
|
|
+ FMTLOG_DEBUG_NON("\n");
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
|