必须设curlopt_upload为1l(非true或1),否则默认get;curlopt_url需含完整ftp://前缀及文件名,缺则误为目录创建;必配curlopt_readfunction与curlopt_readdata,否则无法读取本地文件。

curl_easy_setopt设置FTP上传参数时容易漏掉哪些关键项
不设CURLOPT_UPLOAD为1L,libcurl会默认走GET;不指定CURLOPT_URL的ftp://前缀或结尾斜杠,上传路径可能被误解析为目录创建而非文件写入;漏掉CURLOPT_READFUNCTION和CURLOPT_READDATA,libcurl根本读不到本地文件内容。
常见错误现象:Failed to open file(其实是没注册读回调)、Failed FTP upload(URL末尾缺/filename)、Empty reply from server(服务器拒绝无USER/PASS的匿名连接)。
-
CURLOPT_URL必须完整,例如"ftp://user:pass@host:21/path/to/file.txt",注意用户名密码需URL编码,端口非21时必须显式写出 -
CURLOPT_UPLOAD设为1L,不是true或1(类型错会导致静默失败) -
CURLOPT_READFUNCTION必须提供,哪怕只是转发fread;CURLOPT_READDATA指向FILE*指针 - 若FTP服务器要求被动模式(绝大多数现代服务器),需设
CURLOPT_FTP_USE_EPSV为1L(默认开启,但某些老服务器需关掉)
FILE*读取回调函数怎么写才不会出错
libcurl调用你的read_callback时,只关心返回值和填充的buffer长度,不检查EOF标志位。如果回调返回0且size * nmemb > 0,libcurl认为“数据已尽”,立即结束上传;但如果文件还没读完,就会截断。
典型坑:用fread(buf, 1, size, fp)直接返回,没处理ferror(fp)或feof(fp)——文件读到末尾后再次调用fread会返回0,但libcurl无法区分是“读完了”还是“读失败了”。
size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userdata) {
FILE *fp = static_cast<file>(userdata);
size_t ret = fread(ptr, size, nmemb, fp);
if (ret == 0 && !feof(fp) && !ferror(fp)) {
// 理论上不该发生,但保险起见返回CURLE_AGAIN触发重试
return CURL_READFUNC_ABORT;
}
return ret;
}</file>
- 返回值必须是实际写入
ptr的字节数(ret * size),不能直接返回ret - 遇到
ferror(fp)应返回CURL_READFUNC_ABORT(-1),否则libcurl继续调用导致未定义行为 - 不要在回调里
fclose(fp)——libcurl不负责释放userdata,得在curl_easy_cleanup()之后手动关
如何处理FTP服务器返回的权限拒绝或路径不存在错误
libcurl默认不校验FTP响应码,CURLOPT_FAILONERROR对FTP无效。上传失败时curl_easy_perform()可能仍返回CURLE_OK,必须检查CURLOPT_HEADERFUNCTION捕获的响应头,或更简单地——启用CURLOPT_NOBODY先做一次HEAD探测。
利用农业相机拍摄植物叶片高分辨率图像,通过AI视觉技术检测叶片卷曲方向(向上卷曲或向下卷曲)
实际场景中,530 Not logged in、550 Permission denied、553 Could not create file这些错误都藏在FTP响应行里,不打印verbose几乎看不到。
- 加
CURLOPT_VERBOSE设为1L,调试阶段必开,否则连错在哪都不知道 - 用
CURLOPT_HEADERFUNCTION配合CURLOPT_HEADERDATA收集响应头,匹配"530"、"550"等字符串 - 路径不存在时,部分FTP服务器会自动创建父目录(如vsftpd配
create_home_dir),但多数不会——得提前用ftp://.../path/加CURLOPT_CUSTOMREQUEST "MKD"建目录 - 上传后校验可用
CURLOPT_NOBODY+CURLOPT_FILETIME查服务端文件时间戳,或用CURLOPT_CUSTOMREQUEST "SIZE"比对大小
Windows下用fopen打开中文路径文件为什么总失败
libcurl内部用C标准库读文件,fopen在Windows上默认窄字符接口,传入UTF-8路径会解码失败。即使编译器支持UTF-8源码,fopen("测试.txt", "rb")也会返回NULL。
解决方案不是改libcurl,而是绕过它:用_wfopen打开文件,再用_fileno转成POSIX fd,最后用fdopen套一层FILE*——但这只适用于mingw/msvc混用场景,更稳妥的是统一用二进制内存缓冲。
- 优先用
std::ifstream以std::ios::binary打开,读全内容到std::vector<char></char>,再用CURLOPT_POSTFIELDS上传(适合小文件) - 大文件必须流式读取时,用
MultiByteToWideChar将UTF-8路径转wchar_t*,再调_wfopen,避免窄字符截断 - Linux/macOS无此问题,但要注意路径中空格需用
%20编码,FTP URL本身不支持未编码空格
真正麻烦的从来不是API调用顺序,而是FTP协议本身没有标准错误反馈机制,同一个550错误,可能是权限、磁盘满、路径语法错——得靠verbose日志逐行盯响应字符串。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










