Win10下FindFirstFile通配符匹配异常原因及解决方法
异常触发原因
该异常是Windows系统历史遗留的文件名匹配逻辑叠加8.3短文件名配置差异导致的,并非API故障:
- 从DOS时代延续的
FindFirstFile/FindNextFile系列API默认会同时匹配文件的长文件名和系统自动生成的8.3格式短文件名。当NTFS分区开启8.3短文件名自动生成功能时,所有文件名长度、后缀长度不符合8.3规则(主名最多8字符、后缀最多3字符)的文件,系统都会自动生成一个符合8.3规则的短别名,例如b.qqqt会生成类似B~1.QQQ的短名,这类短名的后缀刚好是.qqq,就会被*.qqq的搜索规则命中,因此会被API返回。 - 不同设备表现不一致的核心原因是8.3短文件名的生成配置不同:Win10不同版本对系统分区、非系统分区的8.3短名默认开启/关闭策略不一样,用户也可以手动通过
fsutil修改该配置,关闭短名生成的分区不会出现该误匹配问题。 - CMD内置的
dir命令直接调用原生Win32枚举API,完全沿用系统的匹配逻辑,因此会复现该问题;PowerShell中的dir是Get-ChildItemcmdlet的别名,其在拿到API返回的所有文件列表后,会在托管层自行实现通配符匹配逻辑,不依赖系统的短名匹配规则,因此结果符合常规预期。
复现问题的Delphi测试代码如下:
{$apptype console} uses Windows; var FindHandle: THandle; FindData: WIN32_FIND_DATA; begin FindHandle := FindFirstFile('*.qqq', FindData); if FindHandle <> INVALID_HANDLE_VALUE then begin try repeat Writeln(PChar(@FindData.cFileName[0])); until not FindNextFile(FindHandle, FindData); finally FindClose(FindHandle); end; end; end.
测试目录下的文件列表:
a.qqq b.qqqt c.qqqx c.qqq123
程序内兼容处理方案
不需要修改系统配置,在程序内部即可实现稳定的预期匹配效果,推荐方案按优先级排序如下:
- 优先方案:枚举结果后自行做严格二次过滤
该方案兼容性覆盖所有Windows版本,完全不受系统配置影响。调用FindFirstFile/FindNextFile拿到所有返回的文件条目后,自行实现通配符匹配逻辑,对返回结构中的cFileName(长文件名)字段做严格规则校验,过滤掉不符合预期的条目即可。
针对*.qqq的场景,严格匹配规则为:文件名最后4个字符必须为.qqq,且.qqq之前的文件名部分不包含路径分隔符、不为空。 - 次选方案:调用新版API禁用短名匹配
在Win10 20H2及以上版本中,可以调用FindFirstFileEx接口,在dwAdditionalFlags参数中传入FIND_FIRST_EX_ONLY_LONG_NAME标志,该标志会告诉API仅匹配长文件名,直接跳过短名匹配逻辑,不需要二次过滤即可得到正确结果。该方案性能更好,但无法兼容更老的Windows版本,建议配合上述二次过滤逻辑做兜底适配。 - 不推荐在应用程序中通过修改系统分区的8.3短名配置解决问题,该操作需要管理员权限,且会影响分区内所有其他程序的行为,副作用不可控。
注意:Win32原生文件枚举API的通配符逻辑存在大量历史兼容设计,除了短名匹配问题外,还存在默认忽略文件名末尾的点、空格等行为,只要业务场景需要严格的文件名匹配,都建议拿到枚举结果后自行实现过滤逻辑,不要依赖系统原生匹配结果。
内容的提问来源于stack exchange,提问作者pepak。
相关产品推荐
相关产品推荐

