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

2022-06-21 15:00:03 浏览数 (1)

一、前言

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协议文件下载成功,通过给定的连接地址,可以完成文件下载,百分比进度返回等等。

代码语言:javascript复制
/**************************************************
作者: 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("创建匿名管道文件失败=%dn", 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("正在执行...GetExitCodeProcessrn");
				GetExitCodeProcess(pi.hProcess, &ExitCode);
				printf("ExitCode:%drn", ExitCode);
				if (ExitCode == STILL_ACTIVE) //正在运行
				{
					DWORD RSize = 0;
					BOOL run_s = 0;
					printf("正在执行...ReadFilern");
					run_s = ReadFile(hReadPipe, pBuffer, sizeof(pBuffer), &RSize, NULL);
					pBuffer[RSize - 1] = '';

					printf("执行过程:%s,%d,%d,%sn", version_str, run_s, RSize, pBuffer);

					char number_buff[10]=""; //存放百分比

					printf("pBuffer=%srn", pBuffer);
					//通过回调函数向外部返回进度提示
					for (size_t i = 0; i < 10 && pBuffer[i]!=''; i  )
					{
						if (pBuffer[i] >= '0' && pBuffer[i] <= '9')
						{
							//得到百分比值
							for (size_t j = 0; j < 9 && pBuffer[i j] != ''; j  )
							{
								//printf("@@%c@@rn", pBuffer[i   j]);
								if (pBuffer[i j] >= '0' && pBuffer[i j] <= '9')
								{
									number_buff[j] = pBuffer[i   j];
								}
								else
								{
									number_buff[j] = '';
									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("回调:%srn", out_str.c_str());
						//将执行的结果再回调出去
						if (func_p)
						{
							func_p(out_str.c_str());
						}
					}
				}
				else //结束
				{
					printf("执行完毕,ExitCode=%drn", ExitCode);
					break;
				}
			}

			printf("正在等待子进程结束....n");
			//等待结束
			WaitForSingleObject(pi.hProcess, INFINITE);

			CloseHandle(pi.hProcess);
			CloseHandle(pi.hThread);
			printf("子进程执行完毕....n");
			return 0;
		}
		printf("子进程创建失败:%dn", 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("文件存储路径:%srn", 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("文件存在不需要下载.rn");
			fclose(file_p);
		}
	}
	return 0;
}

0 人点赞