我需要从 HTTP 服务器下载并保存文件,但我不能使用 libcurl 或任何内置系统库。这是一个适用于 Nintendo 3ds 的程序,可以使用自制软件运行(如果您想知道,我正在使用 devkitpro)。我当前的代码仅在我手动输入下载函数的参数时才有效:
http_download_save("https://web.com/file.txt", "output-file-name.txt"); // <-- WORKS
char url[64] = "https://web.com/file.txt";
char out[64] = "output-file-name.txt";
http_download_save(url, out); // <-- DOESNT WORK, No errors occur but it does not download the file
关于 char url 和 char out 的注释,当我的长度为 248(以前是这样)时,当我尝试删除文件说名称太长时,windows 给了我一个错误,说名称太长了,虽然改变了它到64没修好,下载还是失败。当我手动键入 URL 但使用变量作为输出文件名时,它会生成一个损坏的文件。这是我的下载功能的代码:
Result http_download_save(char *url, char *outfile)
{
Result ret=0;
httpcContext context;
char *newurl=NULL;
u32 statuscode=0;
u32 contentsize=0, readsize=0, size=0;
u8 *buf, *lastbuf;
do {
ret = httpcOpenContext(&context, HTTPC_METHOD_GET, url, 1);
// This disables SSL cert verification, so https:// will be usable
ret = httpcSetSSLOpt(&context, SSLCOPT_DisableVerify);
// Enable Keep-Alive connections
ret = httpcSetKeepAlive(&context, HTTPC_KEEPALIVE_ENABLED);
// Set a User-Agent header so websites can identify your application
ret = httpcAddRequestHeaderField(&context, "User-Agent", "httpc-example/1.0.0");
// Tell the server we can support Keep-Alive connections.
// This will delay connection teardown momentarily (typically 5s)
// in case there is another request made to the same server.
ret = httpcAddRequestHeaderField(&context, "Connection", "Keep-Alive");
ret = httpcBeginRequest(&context);
if(ret!=0){
httpcCloseContext(&context);
if(newurl!=NULL) free(newurl);
return ret;
}
ret = httpcGetResponseStatusCode(&context, &statuscode);
if(ret!=0){
httpcCloseContext(&context);
if(newurl!=NULL) free(newurl);
return ret;
}
if ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308)) {
if(newurl==NULL) newurl = (char*)malloc(0x1000); // One 4K page for new URL
if (newurl==NULL){
httpcCloseContext(&context);
return -1;
}
ret = httpcGetResponseHeader(&context, "Location", newurl, 0x1000);
url = newurl; // Change pointer to the url that we just learned
printf("redirecting to url: %s\n",url);
httpcCloseContext(&context); // Close this context before we try the next
}
} while ((statuscode >= 301 && statuscode <= 303) || (statuscode >= 307 && statuscode <= 308));
if(statuscode!=200){
printf("\x1b[31mAn Error Occured\x1b[0m\n");
httpcCloseContext(&context);
if(newurl!=NULL) free(newurl);
return -2;
}
// This relies on an optional Content-Length header and may be 0
ret=httpcGetDownloadSizeState(&context, NULL, &contentsize);
if(ret!=0){
httpcCloseContext(&context);
if(newurl!=NULL) free(newurl);
return ret;
}
// Start with a single page buffer
buf = (u8*)malloc(0x1000);
if(buf==NULL){
httpcCloseContext(&context);
if(newurl!=NULL) free(newurl);
return -1;
}
do {
// This download loop resizes the buffer as data is read.
ret = httpcDownloadData(&context, buf+size, 0x1000, &readsize);
size += readsize;
if (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING){
lastbuf = buf; // Save the old pointer, in case realloc() fails.
buf = (u8*)realloc(buf, size + 0x1000);
if(buf==NULL){
httpcCloseContext(&context);
free(lastbuf);
if(newurl!=NULL) free(newurl);
return -1;
}
}
} while (ret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING);
if(ret!=0){
httpcCloseContext(&context);
if(newurl!=NULL) free(newurl);
free(buf);
return -1;
}
FILE* out = fopen(outfile, "w");
fwrite(buf, 1, size, out);
fclose(out);
httpcCloseContext(&context);
free(buf);
if (newurl!=NULL) free(newurl);
return 0;
}
提前致谢!