使用curl库能很好的实现文件下载,而且curl库也能直接支持https(编译的时候带好openssl),下面是具体的实现文件下载的过程:
首页,需要定义一个下载任务的结构:
代码语言:javascript复制typedef struct _tagDownTask
{
char url[1024];
char filePath[1024];
unsigned long totalSize;
unsigned long currentFileSize;
unsigned long limitSize; //0为不限制
FILE* pfile; //文件句柄
unsigned long fileSize;
char checkSum[64]; //md5效验码
}DownTask;
接下来具体实现下载函数:
代码语言:javascript复制// 获取当前文件大小
size_t curl_get_filesize(const char* filepath)
{
FILE* fi;
size_t sz;
fi = fopen(filepath, "r");
if (!fi) return 0;
fseek(fi, 0L, SEEK_END);
sz = ftell(fi);
fseek(fi, 0L, SEEK_SET);
fclose(fi);
return sz;
}
//功能:效验文件
int curl_checkSum(char* filepath, char* checkSum)
{
K_INT32 lRet = 0;
K_CHAR md5[64] = { 0 };
//生成文件md5码并比较
//to do 这里的代码就不实现了
return lRet;
}
// 回调函数,用于处理Curl库接收到的数据
size_t curl_write_callback(void *buffer, size_t size, size_t nmemb, void *userdata) {
DownTask* pTask = (DownTask*)userdata;
size_t written = fwrite(buffer, size, nmemb, pTask->pfile);
//分别增加统计
pTask->totalSize = written;
pTask->currentFileSize = written;
// 检查已下载的字节数是否超过限制,如果超过则返回 0,停止下载
if (pTask->limitSize > 0 && pTask->totalSize >= pTask->limitSize) {
return 0;
}
return written;
}
// 添加一个curl下载任务
int curl_download(DownTask *in_pDownTask)
{
CURL *curl;
CURLcode res;
int lRet = 0;
char range_header[64];
//获取已下载文件的大小
in_pDownTask->currentFileSize = curl_get_filesize(in_pDownTask->filePath);
// 以追加二进制模式打开文件,实现断点续传
in_pDownTask->pfile = fopen(in_pDownTask->filePath, "ab");
if (!in_pDownTask->pfile) {
fprintf(stderr, "Error opening file.n");
return -1;
}
// 初始化Curl库
curl_global_init(CURL_GLOBAL_DEFAULT);
// 创建Curl句柄
curl = curl_easy_init();
if (curl) {
// 设置要下载的URL
curl_easy_setopt(curl, CURLOPT_URL, in_pDownTask->url);
// 设置回调函数,处理接收到的数据
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback);
// 将文件句柄传递给回调函数
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)in_pDownTask);
// 设置断点续传的起始位置
if (in_pDownTask->currentFileSize > 0) {
snprintf(range_header, sizeof(range_header), "Range: bytes=%d-", in_pDownTask->currentFileSize);
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, (long)in_pDownTask->currentFileSize);
}
else {
curl_easy_setopt(curl, CURLOPT_RESUME_FROM, 0);
}
curl_easy_setopt(curl, CURLOPT_HEADERDATA, NULL);
// 禁用SSL证书验证
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
// 执行Curl请求
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "Curl failed: %sn", curl_easy_strerror(res));
}
// 清理Curl句柄
curl_easy_cleanup(curl);
}
// 关闭文件
fclose(in_pDownTask->pfile);
// 清理Curl全局资源
curl_global_cleanup();
//下载完成
if (in_pDownTask->fileSize == in_pDownTask->currentFileSize) {
//效验检查
lRet = curl_checkSum(in_pDownTask->filePath, in_pDownTask->checkSum);
if (lRet == 0) {
return 0;
}
//不通过则删除已下数据
remove(in_pDownTask->filePath);
return -1;
}
//未完成,下次断点续传
else if (in_pDownTask->fileSize > in_pDownTask->currentFileSize) {
return 1;
}
else {
//不通过则删除已下数据
remove(in_pDownTask->filePath);
return -1;
}
}
使用时直接调用:
代码语言:javascript复制DownTask task = {0};
sprintf(task.url, "%s", "https://yoururl.com/file.zip");
task.limitSize = 0;
task.fileSize = 123; //你的文件大小
sprintf(task.checkSum, "%s", "your file md5");
sprintf(task.filePath, "%s", "your save path");
curl_download(&task);