std::filesystem无法解析ftp list响应,因其仅支持本地文件系统操作;list格式无统一标准,需手动识别unix/windows等风格并用正则或列索引解析,推荐优先使用标准化的mlsd命令。

FTP LIST 响应没有标准格式,别指望 std::filesystem 能直接解析
FTP 的 LIST 命令返回的是服务器自定义的目录列表文本,不是 JSON 或 XML,也没有统一规范。Unix 风格(ls -l)、DOS 风格(dir)、甚至精简模式都可能共存。C++ 标准库完全不提供 FTP 解析能力,std::filesystem 只能操作本地路径,对 FTP 响应束手无策。
你得自己拆字段,而且必须先知道服务器用的是哪种格式 —— 这通常只能靠试探或文档确认。
先识别 LIST 响应类型:看首行或尝试匹配常见模式
不同服务器返回的首行特征差异很大:drwxr-xr-x 开头基本是 Unix 风格;01-01-20 12:34PM <dir> foo</dir> 是 Windows IIS;total 12 行存在则大概率是 Unix 类;空行后紧跟文件行也可能是类 Unix。
- 不要硬写一个“通用解析器”——它要么漏字段,要么误判权限/大小/时间
- 优先查目标 FTP 服务文档(如 vsftpd、ProFTPD、FileZilla Server 的默认 LIST 格式)
- 实际抓包看真实响应:用
telnet host 21手动发USER/PASS/LIST,观察原始输出 - 若支持
MLSD(RFC 3659),坚决用它替代LIST:返回固定格式的机器可读数据,字段带前缀如modify=20230101123456;size=1024;type=file;foo.txt
Unix 风格 LIST 解析:按空格切分不可靠,要用正则或字段位置锚定
典型行:drwxr-xr-x 2 user group 4096 Jan 01 12:34 dirname。看似空格分隔,但文件名含空格就崩了(如 my file.txt)。正确做法是依赖固定列宽或正则捕获组。
推荐用正则(C++11 std::regex)匹配:
^([dl-][rwx-]{9})\s+\d+\s+\S+\s+\S+\s+(\d+)\s+([A-Za-z]{3}\s+\d{1,2}\s+\d{2}:\d{2}|\d{3,4})\s+(.+)$
注意:
-
\d{3,4}匹配年份(4位)或大小(3–4位),需结合上下文判断:若该数字 > 10000 且后续是月份缩写(Jan等),大概率是大小;否则可能是年份 - 时间字段格式不统一:
Jan 01 12:34、Jan 01 2023、Jan 01 12:34 PM都存在,std::get_time对空格敏感,建议用strptime(POSIX)或手动解析 - 权限字符串
drwxr-xr-x第 1 字符是d(目录)、-(普通文件)、l(符号链接),后面 9 位按 3 组解析即可
Windows 风格 LIST 解析:字段对齐靠空格数量,别信 std::stringstream >>
典型行:01-01-20 12:34PM <dir> foo</dir>。关键点在于列是右对齐/左对齐的固定宽度,中间用多个空格分隔。
安全做法是按列索引提取:
- 日期在 [0,7](8 字符),时间在 [9,16](8 字符),
<dir></dir>在 [18,24](7 字符),文件名从 [26] 开始直到末尾 - 用
substr()硬截取,比用std::istringstream按空格 split 更可靠 -
<dir></dir>存在即为目录;否则是文件,大小字段紧挨着时间之后(如01-01-20 12:34PM 12345 file.bin) - 注意 AM/PM 大小写和空格:
12:34PM和12:34 PM都可能出现
真正麻烦的不是解析本身,而是你得为每种见过的 FTP 服务器维护一套规则。生产环境建议封装成策略类,按服务器指纹(banner 或已知行为)自动选择解析器。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











