写点什么

windows 下 C 语言使用 curl 库访问 HTTP 下载文件

作者:DS小龙哥
  • 2022 年 5 月 20 日
  • 本文字数:2988 字

    阅读完需:约 10 分钟

一、前言

cURL 是一个利用 URL 语法在命令行下工作的文件传输工具,1997 年首次发行。它支持文件上传和下载,所以是综合传输工具,但按传统,习惯称 cURL 为下载工具。cURL 还包含了用于程序开发的 libcurl。


cURL 支持的通信协议有 FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3、SMTP 和 RTSP。


curl 还支持 SSL 认证、HTTP POST、HTTP PUT、FTP 上传, HTTP form based upload、proxies、HTTP/2、cookies、用户名+密码认证(Basic, Plain, Digest, CRAM-MD5, NTLM, Negotiate and Kerberos)、file transfer resume、proxy tunneling。

二、curl 下载

curl for windows : https://curl.se/windows/


下载页面如图:




解压后的可执行文件位置:



下面是解压后的文件目录:



在命令行使用 curl 测试下载文件:


三、通过命令行使用 curl

curl 可以直接调用函数库完成功能设计、也可以直接调用可执行文件完成需要的功能,下面这里就介绍,在 windows 下,通过CreateProcess调用 curl 命令函数完成文件下载。使用 curl 实现 HTTP 协议文件下载成功,通过给定的连接地址,可以完成文件下载,百分比进度返回等等。


/**************************************************作者: DS小龙哥功能: 执行命令参数解释:CallBackFunction_p func_p  :回调函数,用于通知进度执行过程char *text  //进度的转码过程,详细描述.描述当前这个操作是做什么.char *total_time   //执行的总时间char *cmd //执行的命令**************************************************/int file_down_func(CallBackFunction_p func_p, const char *text, const char *total_time, const  char *cmd){    BOOL run_pipe;
PROCESS_INFORMATION pi; STARTUPINFO si; BOOL ret = FALSE; DWORD flags = CREATE_NO_WINDOW;

char pBuffer[210]; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; HANDLE hReadPipe, hWritePipe; run_pipe = CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
if (run_pipe != 1) { printf("创建匿名管道文件失败=%d\n", run_pipe); return -1; }
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = NULL; si.hStdError = hWritePipe; si.hStdOutput = hWritePipe;
wchar_t cmd_wchar[1024]; CharToWchar(cmd, cmd_wchar);
//TCHAR cmd[] = TEXT("ffmpeg -i D:\\123.mp4 -vf reverse D:\\out\\out1.mp4");
ret = CreateProcess(NULL, cmd_wchar, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);
if (ret) { while (true) { DWORD ExitCode = 0; //判断进程是否执行结束 printf("正在执行...GetExitCodeProcess\r\n"); GetExitCodeProcess(pi.hProcess, &ExitCode); printf("ExitCode:%d\r\n", ExitCode); if (ExitCode == STILL_ACTIVE) //正在运行 { DWORD RSize = 0; BOOL run_s = 0; printf("正在执行...ReadFile\r\n"); run_s = ReadFile(hReadPipe, pBuffer, sizeof(pBuffer), &RSize, NULL); pBuffer[RSize - 1] = '\0';
printf("执行过程:%s,%d,%d,%s\n", version_str, run_s, RSize, pBuffer);
char number_buff[10]="\0"; //存放百分比
printf("pBuffer=%s\r\n", pBuffer); //通过回调函数向外部返回进度提示 for (size_t i = 0; i < 10 && pBuffer[i]!='\0'; i++) { if (pBuffer[i] >= '0' && pBuffer[i] <= '9') { //得到百分比值 for (size_t j = 0; j < 9 && pBuffer[i+j] != '\0'; j++) { //printf("@@%c@@\r\n", pBuffer[i + j]); if (pBuffer[i+j] >= '0' && pBuffer[i+j] <= '9') { number_buff[j] = pBuffer[i + j]; } else { number_buff[j] = '\0'; break; } } break; } }
// 0 926M 0 6463k 0 0 7378k 0 0:02:08 --:--:-- 0:02:08 7386 //如果找到进度的位置 if (strlen(number_buff)>0) { std::string out_str;
out_str = text; out_str += ","; out_str += "100"; out_str += ","; out_str += number_buff;
printf("回调:%s\r\n", out_str.c_str()); //将执行的结果再回调出去 if (func_p) { func_p(out_str.c_str()); } } } else //结束 { printf("执行完毕,ExitCode=%d\r\n", ExitCode); break; } }
printf("正在等待子进程结束....\n"); //等待结束 WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess); CloseHandle(pi.hThread); printf("子进程执行完毕....\n"); return 0; } printf("子进程创建失败:%d\n", ret); return -1;}


int main(){ string VideoCacheFilePath = "D:\\out";
//下载的文件名称 string file_path = "http://192.168.1.110:8001/Uploads/1/哈哈哈.MP4";
//如果返回为真就表示是网络地址 if (strstr(file_path.c_str(), "http:") || strstr(file_path.c_str(), "https:")) { //1.获取不带路径的文件名 string::size_type iPos; if (strstr(file_path.c_str(), "\\")) { iPos = file_path.find_last_of('\\') + 1; } else { iPos = file_path.find_last_of('/') + 1; }
//得到文件名称 string base_file = file_path.substr(iPos, file_path.length() - iPos);
//得到完整的文件下载存储路径 string VideoPath_tmp = VideoCacheFilePath; VideoPath_tmp += "\\"; VideoPath_tmp += base_file;
//判断文件是否存在 printf("文件存储路径:%s\r\n", VideoPath_tmp.c_str()); FILE *file_p = fopen(VideoPath_tmp.c_str(),"rb"); //不存在就下载 if (file_p == nullptr) { //切换目录,进入到curl命令所在的目录 _chdir(VideoCacheFilePath.c_str());
string cmd = "curl -O "; cmd += file_path; //启动下载文件 file_down_func(NULL, base_file.c_str(),"100",cmd.c_str()); } else { printf("文件存在不需要下载.\r\n"); fclose(file_p); } } return 0;}
复制代码


发布于: 2022 年 05 月 20 日阅读数: 2
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
windows下C语言使用curl库访问HTTP下载文件_5月月更_DS小龙哥_InfoQ写作社区