应使用 Path.GetExtension 而非手动解析:它安全处理空值、多点名(如 .tar.gz)、点开头文件(如 .gitignore)、大小写及末尾点等边界情况,返回带前导点的扩展名,且不访问磁盘;需无点时用 Substring(1) 提取,切勿 TrimStart;扩展名不能用于类型校验,须结合 ContentType 或魔数。

直接用 Path.GetExtension,别自己切字符串或依赖文件名后缀逻辑——它已处理空值、点号位置异常、多点名(如 archive.tar.gz)等边界情况。
为什么不用 string.LastIndexOf('.') + substring
手动解析看似可控,实则埋雷:
-
FileNameWithoutDot会返回空字符串,string.Substring报ArgumentOutOfRangeException - 文件名以点开头(如
.gitignore)时,Path.GetExtension正确返回".gitignore",而LastIndexOf可能误判为无扩展名 -
file.name.txt.bak这类多点名,Path.GetExtension返回".bak"(符合 Windows 和 .NET 约定),手写逻辑常错取成".txt.bak"或".name.txt.bak" - 不区分大小写场景下(如某些 Linux 文件系统挂载为 NTFS),
Path.GetExtension返回原样小写/大写,但后续比对需额外处理;手动截取不会自动帮你统一大小写
Path.GetExtension 的行为细节与陷阱
这个方法只看路径字符串本身,不访问磁盘,也不校验文件是否存在。它的返回值有明确契约:
- 输入为
null或空字符串 → 返回空字符串"",不是null - 输入不含
'.'→ 返回空字符串""(例如"README") - 输入以
'.'结尾(如"log.")→ 返回"."(注意:这是一个合法扩展名,长度为 1) - 输入是目录路径(如
"C:\Data\Reports\")→ 返回空字符串"",即使末尾有反斜杠也不影响判断逻辑 - 扩展名不强制含字母数字;
"file..config"返回".config"(取最后一个点之后全部)
需要“纯扩展名”(不含点)?自己 TrimStart 就行
Path.GetExtension 总是带前导点,这是设计使然(和系统 API 对齐)。如果业务逻辑要求无点扩展名(比如映射 MIME 类型、查字典键),别封装新函数,直接:
string extWithDot = Path.GetExtension(fileName); string extWithoutDot = extWithDot.Length > 0 ? extWithDot.Substring(1) : string.Empty;
注意不要用 TrimStart('.') —— 它对 "..tar" 会错误变成 "tar",而实际应为 ".tar"(即 Path.GetExtension 返回 ".tar",Substring(1) 才得 "tar")。
真正容易被忽略的是:扩展名只是文件名的一部分,它不保证文件真实类型。上传场景中,仅靠 Path.GetExtension 做安全校验是无效的——必须结合 ContentType、魔数(file signature)或临时解码验证。这个方法只解决「怎么从字符串里安全抠出扩展名」这一个子问题,别让它超纲干活。


















