使用 CURLOPT_WILDCARDMATCH 实现 libcurl 的 FTP 目录通配符批量下载

📅 发布时间:2026/9/11 16:51:45
使用 CURLOPT_WILDCARDMATCH 实现 libcurl 的 FTP 目录通配符批量下载
使用 CURLOPT_WILDCARDMATCH 实现 libcurl 的 FTP 目录通配符批量下载【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curlCURLOPT_WILDCARDMATCH是 libcurl 提供的目录通配符传输开关开启后URL 末尾的文件名部分可以使用类似 shell 的fnmatch通配符模式如ftp://example.com/some/path/*.txtlibcurl 会先列出远程目录再自动批量下载所有匹配的文件。本指南以 curl 仓库中的 CURLOPT_WILDCARDMATCH 手册 为主体结合 lib/ftp.c、lib/curl_fnmatch.c 与 include/curl/curl.h 的源码实现完整讲解模式语法、回调协作机制与底层状态机帮助读者用 libcurl 实现类似 FTP 批量镜像、日志收集、按日期规则取文件等实战需求。选项总览#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WILDCARDMATCH, long onoff);作用开启/关闭目录通配符传输。将onoff设为1即按文件名模式传输多个文件设为0默认值则关闭。适用协议仅 FTP该选项在#ifndef CURL_DISABLE_FTP保护块内定义与生效。加入版本7.21.0。模式来源通配符模式作为CURLOPT_URL中 URL 末尾的文件名部分给出即最后一个/之后的内容被视为模式。从源码看该选项最终落到struct Curl_easy的set结构体中在 lib/setopt.c 中case CURLOPT_WILDCARDMATCH:将参数直接写入s-wildcard_enabled对应 lib/urldata.h 中的BIT(wildcard_enabled); /* enable wildcard matching */字段。同时 lib/easyoptions.c 将该选项登记为CURLOT_LONG类型因此调用形式必须是curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L)这样的long值。模式语法fnmatch 风格的通配符开启通配符后URL 的最后一段文件名部分按 shell 模式匹配规则解析。libcurl 默认使用自己的内部匹配实现若系统提供了fnmatch也可选择调用系统实现见下文底层实现一节。以下语法说明完整摘自原手册。*星号匹配任意多个字符包括零个。例如ftp://example.com/some/path/*.txt匹配该目录下所有.txt文件。注意限制同一个模式字符串中最多只允许出现两个星号。?问号匹配任意恰好一个字符。例如ftp://example.com/some/path/photo?.jpg可匹配photo1.jpg、photoa.jpg等但不会匹配photo.jpg缺少一个字符或photo10.jpg多出一个字符。[左方括号括号表达式左方括号开启一个括号表达式bracket expression表达式以右方括号]结束整体匹配恰好一个字符。括号表达式内部?和*不再具有特殊含义只按普通字符处理。支持以下几种写法字符区间[a-zA-Z0-9]或[f-gF-G]匹配区间内的任意一个字符。字符枚举[abc]匹配a、b、c中的任意一个。否定[^abc]或[!abc]匹配除a、b、c之外的任意一个字符。字符类class expression[[:name:]]支持以下 11 个类alnum、lower、space、alpha、digit、print、upper、blank、graph、xdigit。特殊情况[][-!^]匹配-、]、[、!或^这五个字面字符——它们在括号表达式中不承担特殊用途仅按普通字符处理。转义语法[[]]用于匹配[、]或e。综合运用上述规则可以构造复杂模式例如ftp://example.com/some/path/[a-z[:upper:]\\].jpg该模式要求文件名第一个字符是小写字母、大写字母通过[:upper:]类、[、]或\\\表示转义后的反斜杠随后紧跟.jpg后缀。底层实现curl 仓库的 lib/curl_fnmatch.c 提供了上述语法的内部实现其函数声明位于 lib/curl_fnmatch.hint Curl_fnmatch(void *ptr, const char *pattern, const char *string);从源码结构可以推断出以下实现细节该文件头部注释lib/curl_fnmatch.c第 30 行附近说明它以递归回溯recursive backtracking方式实现#ifndef HAVE_FNMATCH表明当平台自带fnmatch如 glibc 提供的 POSIXfnmatch(3)时可以编译期切换到系统实现否则使用 curl 内置版本这保证了在不同嵌入式与桌面平台上的可移植性。内置实现通过一组常量把字符类映射为伪字符例如CURLFNM_ALNUM、CURLFNM_DIGIT、CURLFNM_XDIGIT、CURLFNM_ALPHA、CURLFNM_PRINT、CURLFNM_BLANK、CURLFNM_LOWER、CURLFNM_GRAPH、CURLFNM_SPACE等lib/curl_fnmatch.c它们与手册中列出的[[:name:]]字符类一一对应正是这些类的底层支撑。CURLFNM_CHSET_SIZE定义为256 15字节的字符集位图用于在括号表达式内快速判定字符是否命中区间/枚举/否定集合。回调协作过滤与分段处理通配符传输并不是简单地一次性拉取全部文件而是通过三个回调与 libcurl 协作实现逐个文件决策 逐个文件下载的流程选项回调时机CURLOPT_CHUNK_BGN_FUNCTION每个具体文件开始下载之前被调用CURLOPT_CHUNK_END_FUNCTION每个文件的数据传输结束之后被调用CURLOPT_FNMATCH_FUNCTION用自定义匹配逻辑替代内部模式匹配可选这些回调指针存储在 lib/urldata.h 的chunk_bgn、chunk_end、fnmatch、fnmatch_data、wildcardptr字段中并在 lib/setopt.c 中分别登记。起始回调curl_chunk_bgn_callbacktypedef long (*curl_chunk_bgn_callback)(const void *transfer_info, void *ptr, int remains);定义于 include/curl/curl.h。transfer_info携带远程文件信息可转型为struct curl_fileinfo *查看文件名、大小、mtime 等ptr是CURLOPT_WILDCARDPTR传入的用户指针remains表示列表中剩余文件数量。返回值含义include/curl/curl.h返回值含义CURL_CHUNK_BGN_FUNC_OK(0)正常下载当前文件CURL_CHUNK_BGN_FUNC_FAIL(1)中止整个通配符任务CURL_CHUNK_BGN_FUNC_SKIP(2)跳过当前文件继续处理下一个结束回调curl_chunk_end_callbacktypedef long (*curl_chunk_end_callback)(void *ptr);定义于 include/curl/curl.h同一行号区域在单个文件传输结束后调用可用于统计下载数量、汇总大小、记录日志等。自定义匹配回调curl_fnmatch_callbacktypedef int (*curl_fnmatch_callback)(void *ptr, const char *pattern, const char *string);定义于 include/curl/curl.h。当CURLOPT_FNMATCH_FUNCTION被设置时libcurl 不再使用内部匹配实现而是把模式与每个远程文件名交给该回调裁决。返回CURL_FNMATCHFUNC_MATCH(0) 表示文件名匹配模式include/curl/curl.h应下载返回非匹配值则跳过。这为需要大小写不敏感匹配、正则式扩展匹配或白名单过滤的场景提供了灵活性。完整示例原手册给出的示例骨架如下它展示了通配符选项与两个块回调的组合extern long begin_cb(struct curl_fileinfo *, void *, int); extern long end_cb(void *ptr); int main(void) { CURL *curl curl_easy_init(); if(curl) { /* turn on wildcard matching */ curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L); /* callback is called before download of concrete file started */ curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, begin_cb); /* callback is called after data from the file have been transferred */ curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, end_cb); /* See more on https://curl.se/libcurl/c/ftp-wildcard.html */ } }将其扩展为可运行版本需要补上 URL、写文件回调与用户指针#include curl/curl.h #include stdio.h /* 每个文件下载前调用remains 为剩余文件数 */ static long begin_cb(const void *transfer_info, void *ptr, int remains) { const struct curl_fileinfo *fi transfer_info; printf(开始下载: %s (剩余 %d 个文件)\n, fi-filename, remains); return CURL_CHUNK_BGN_FUNC_OK; } /* 每个文件下载完成后调用 */ static long end_cb(void *ptr) { long *count ptr; (*count); printf(完成下载累计 %ld 个文件\n, *count); return CURL_CHUNK_END_FUNC_OK; } int main(void) { CURL *curl curl_easy_init(); long done 0; if(curl) { curl_easy_setopt(curl, CURLOPT_URL, ftp://example.com/some/path/*.txt); curl_easy_setopt(curl, CURLOPT_WILDCARDMATCH, 1L); curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, begin_cb); curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, end_cb); curl_easy_setopt(curl, CURLOPT_WILDCARDPTR, done); /* 还可设置 CURLOPT_WRITEFUNCTION/CURLOPT_WRITEDATA 决定文件落盘方式 */ CURLcode res curl_easy_perform(curl); if(res ! CURLE_OK) fprintf(stderr, wildcard transfer failed: %s\n, curl_easy_strerror(res)); curl_easy_cleanup(curl); } return 0; }注意CURL_CHUNK_END_FUNC_OK与CURL_CHUNK_BGN_FUNC_OK均为 0代表正常继续。编译时链接-lcurl即可。底层状态机一次批量传输如何运转通配符传输在 libcurl 内部由一个有限状态机FSM驱动实现在 lib/ftp.c 的ftp_do_more相关逻辑中约 lib/ftp.c。从源码看struct WildcardData是保存匹配状态的载体lib/urldata.h其状态流转大致如下CURLWC_CLEAN初始状态。libcurl 从 URL 的最后一个/之后提取模式串wildcard-pattern curlx_strdup(last_slash)并分配 FTP 协议专用的通配符数据wildcard-ftpwc。CURLWC_MATCHING发送 FTP 列表命令收集远程目录条目逐一与模式比对命中者进入文件列表wildcard-filelist链表。CURLWC_DOWNLOADING从链表头部依次取出文件拼接完整路径后发起下载下载前调用chunk_bgn回调——若返回CURL_CHUNK_BGN_FUNC_SKIP则状态切到CURLWC_SKIP若返回CURL_CHUNK_BGN_FUNC_FAIL则整体失败下载完成后调用chunk_end回调并移除链表节点lib/ftp.c。CURLWC_SKIP / CURLWC_DONE / CURLWC_ERROR跳过、全部完成或出错时的终止状态结束时通过wildcard-dtor释放协议数据。当data-state.wildcardmatch为真且状态机进入CURLWC_SKIP或CURLWC_DONE时后续传输逻辑会被短路lib/ftp.c同时ftp_done_wildcardlib/ftp.c负责在每次传输收尾时清理并调用chunk_end。这一设计解释了为何CHUNK_END_FUNCTION会在整个批次结束时也被调用一次用于收尾统计。注意事项通配符模式只能出现在 URL 末尾的文件名部分不能对中间路径段使用模式以最后一个/为界提取。同一个模式字符串内最多两个星号超出部分会被拒绝或无法按预期匹配。选项仅对 FTP 生效对其他协议HTTP、SFTP 等设置该选项不会启用批量匹配。开启通配符后若同时使用CURLOPT_FTP_SKIP_PASV_IP之类的 FTP 选项需要注意通配符路径与CURLOPT_NOCWD的兼容性源码注释明确wildcard does not support NOCWD option见 lib/ftp.c 附近。若不想依赖内部实现可通过CURLOPT_FNMATCH_FUNCTION提供自定义匹配函数匹配语义完全由回调决定。返回值curl_easy_setopt(CURL *handle, CURLOPT_WILDCARDMATCH, ...)返回CURLcodeCURLE_OK(0) 表示设置成功非零值表示出错具体错误码参见libcurl-errors(3)。延伸阅读CURLOPT_URL 手册模式所在的 URL 如何构造CURLOPT_CHUNK_BGN_FUNCTION 手册 与 CURLOPT_CHUNK_END_FUNCTION 手册两个块回调的完整签名与返回码约定CURLOPT_FNMATCH_FUNCTION 手册自定义模式匹配的入口源码lib/ftp.cFSM 驱动、lib/curl_fnmatch.c内部匹配器、lib/urldata.h状态与回调存储【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考