libcurl 获取远程文件时间:CURLINFO_FILETIME 用法与底层实现解析
2026/9/11 11:59:22 网站建设 项目流程

libcurl 获取远程文件时间:CURLINFO_FILETIME 用法与底层实现解析

【免费下载链接】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

导读

CURLINFO_FILETIME是 libcurl 提供的信息查询选项,用于在传输完成后读取远端文档的最后修改时间(以自 1970-01-01 00:00:00 UTC 起的秒数表示)。它通常与CURLOPT_FILETIME配合使用,适用于 HTTP、FTP、SFTP、FILE、SMB 等协议下需要展示或校验文件时间戳的场景。读完本文,你将掌握该选项的完整调用方式、返回值语义、各协议的底层实现机制,以及如何规避 32 位long带来的 2038 年问题。

一、函数签名与基本语义

CURLINFO_FILETIMEcurl_easy_getinfo(3)的查询类型之一,官方声明位于 docs/libcurl/opts/CURLINFO_FILETIME.md,自 libcurl 7.5 起加入:

#include <curl/curl.h> CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FILETIME, long *timep);

调用时传入一个long *指针,libcurl 会将远端文档的时间写入该指针,单位为自 1970 年 1 月 1 日起的秒数(GMT/UTC 时区)。需要特别注意的是返回值-1的语义:它并不代表某个确定的历史时间,而是表示"文档时间未知"。官方文档明确指出,得到-1可能由多种原因造成:

  • 服务器未提供该信息(例如 HTTP 响应中没有Last-Modified头);
  • 服务器主动隐藏了文件时间;
  • 服务器不支持获取文档时间的命令(如 FTP 服务器不支持MDTM扩展命令);
  • 传输未成功完成等。

二、关键前置条件:必须先开启 CURLOPT_FILETIME

这是使用本选项最容易踩的坑:必须在发起传输之前通过curl_easy_setopt设置CURLOPT_FILETIME为 1(启用),否则无条件得到-1。文档中的原话是"You must ask libcurl to collect this information before the transfer is made",其语义与"时间信息采集开关"一致——libcurl 只有在收到显式请求时才会在传输过程中解析并保存时间戳。

从源码实现看,CURLOPT_FILETIME在 lib/setopt.c 中被处理为:

case CURLOPT_FILETIME: /* * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ s->get_filetime = enabled; break;

它写入struct Curl_easyset.get_filetime布尔位(定义见 lib/urldata.h)。该开关会被各协议的状态机读取,决定是否主动采集时间;采集到的结果保存到data->info.filetime(类型为time_t),供后续curl_easy_getinfo读取。

三、各协议的底层采集机制

get_filetime开关在不同协议中的处理方式各不相同,理解这些细节有助于判断"为什么我拿到的还是 -1"。

3.1 HTTP:解析 Last-Modified 响应头

HTTP 场景下,libcurl 在解析响应头时专门匹配Last-Modified:字段。核心逻辑位于 lib/http.c 的http_header_l()

const char *v = (!k->http_bodyless && (data->set.timecondition ||>case CURLINFO_FILETIME: if(data->info.filetime > LONG_MAX) *param_longp = LONG_MAX; else if(data->info.filetime < LONG_MIN) *param_longp = LONG_MIN; else *param_longp = (long)data->info.filetime; break;

CURLINFO_FILETIME_T使用curl_off_t(64 位)返回完整值,见 lib/getinfo.c:

case CURLINFO_FILETIME_T: *param_offt = (curl_off_t)data->info.filetime; break;

对于跨平台或长期运行的程序,优先使用CURLINFO_FILETIME_T是更稳妥的选择;CURLINFO_FILETIME适合在明确不涉及 2038 年之后的场景下使用。

五、完整可运行示例

原文档提供了可直接编译运行的 C 示例,这里完整保留并补充注释:

#include <stdio.h> #include <time.h> #include <curl/curl.h> int main(void) { CURL *curl = curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); /* Ask for filetime:必须先开启,否则 CURLINFO_FILETIME 无条件返回 -1 */ curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); result = curl_easy_perform(curl); if(result == CURLE_OK) { long filetime = 0; result = curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime); if((result == CURLE_OK) && (filetime != -1)) { /* filetime 为自 1970-01-01 UTC 起的秒数,-1 表示时间未知 */ time_t file_time = (time_t)filetime; printf("filetime: %s", ctime(&file_time)); } else { printf("filetime unknown (result=%d, filetime=%ld)\n", (int)result, filetime); } } /* always cleanup */ curl_easy_cleanup(curl); } return 0; }

编译方式(假设已安装 libcurl 开发包):

cc -o filetime filetime.c -lcurl

运行后若服务器返回Last-Modified头,程序会输出类似filetime: Wed Sep 9 04:45:53 2026的可读时间;否则提示时间未知。

六、返回值与错误处理

curl_easy_getinfo(3)返回CURLcode,具体到本选项:

  • CURLE_OK (0):查询成功,timep被写入有效值(也可能是-1,代表时间未知,这不算错误);
  • 非零:发生了错误,例如handle非法或调用时机不对,详细错误码参见libcurl-errors(3)

实际编码时建议像示例一样同时检查返回码与-1哨兵值:返回CURLE_OK只表示"查询动作成功执行",并不保证远端时间一定可用。另外注意,CURLINFO_FILETIME查询到的时间类型是long,转换为time_t后可直接配合ctime()gmtime()等标准库函数使用。

七、小结与最佳实践

  1. 先开后查:传输前必须curl_easy_setopt(curl, CURLOPT_FILETIME, 1L),否则结果恒为-1
  2. 协议依赖:HTTP 依赖Last-Modified头、FTP 依赖MDTM命令、SFTP 依赖文件属性mtime、FILE 依赖stat(),服务器不支持时无法获得时间;
  3. 警惕 2038:在 32 位long平台优先使用CURLINFO_FILETIME_T
  4. 区分"未知"与"错误"-1是合法输出而非失败,判断失败要看curl_easy_getinfo的返回值。

相关配套文档可进一步阅读 CURLOPT_FILETIME(设置采集开关)、CURLINFO_FILETIME_T(64 位时间查询)以及 curl_easy_getinfo(查询 API 总览)。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询