在C#中使用通配符查找文件

17

我正在尝试从一个目录中查找文件:

String[] search1 = Directory.GetFiles(voiceSource, "85267-*.wav")
                                 .Select(path => Path.GetFileName(path))
                                 .ToArray();

String[] search2 = Directory.GetFiles(voiceSource, "85267 *.wav")
                                 .Select(path => Path.GetFileName(path))
                                 .ToArray();

但是在search1中,它选择了85267-s.wav85267 -s.wav。但我只想选择85267-s.wav

search2表现良好。

我该怎么做呢?


1
使用 '?' 作为通配符。 - Jodrell
3
@adv12: 是吗?星号在减号后面而不是前面。 - Tim Schmelter
1
在命令提示符中,>dir 85267-*.wav 返回了两个文件。看起来好像出了问题。 - Habib
1
建议使用Directory.EnumerateFiles而不是Directory.GetFiles。https://msdn.microsoft.com/zh-cn/library/system.io.directory.enumeratefiles(v=vs.110).aspx - Jodrell
6
目录搜索同时匹配长文件名和短文件名。使用“dir /x”命令查看短文件名。“85267-s.wav”的短文件名可能是“85267-~1.wav”,正是这个短文件名在进行匹配。 - Raymond Chen
显示剩余6条评论
2个回答

8

是的,这是MS-Dos 8.3短文件名支持的副作用,在大多数文件系统上今天仍然保留。你可以通过DIR /X命令查看到这些短文件名。在我的机器上:

C:\temp>dir /x *.wav

01/21/2015  09:11 AM                 6 85267-~1.WAV 85267 -s.wav
01/21/2015  09:11 AM                 6              85267-s.wav
               2 File(s)             12 bytes
               0 Dir(s)  235,121,160,192 bytes free

请注意,“85267 -s”的简短名称中缺少空格。这不是简短名称中有效的字符。现在剩下的内容也与通配符匹配。
这些简短名称的问题并不止于此,像“*.wav”这样的通配符也会匹配完全不同文件类型的文件,比如“foobar.wavx”。
简短名称生成实际上是上个世纪的遗物,今天应该被关闭。但通常你无法自行控制。你必须处理这些意外匹配并仔细检查返回的内容。例如,使用正则表达式。

1
或许框架应该让你选择想要搜索哪种类型的文件名? - Jodrell
好的,实现方式并不是这样的。框架只是将通配符传递给操作系统。它以这种方式工作非常重要,因为文件系统驱动程序进行过滤处理会更快。 - Hans Passant
好的,如果文件系统驱动程序...等等,我可以看到这会导致什么。我参考您的答案。 - Jodrell
非常有趣!我不知道现代Windows操作系统仍在使用MS-DOS短文件名,尤其是它们不再基于DOS。是否有计划停止对此的支持,例如Windows 10? - Saggio
1
告诉人们停止使用他们20多年前的业务关键应用程序,这种应用程序没有支持,也没有程序员可以修改,这不是微软的策略。顺便说一句,这很常见,我自己也写了很多,据我所知,大部分仍在运行。 - Hans Passant

8
您遇到的问题是由于短文件名引起的。由于您会得到85267-~1.WAV,而这与您的通配符"85267-*.wav"匹配,因此您会得到两个文件。
这在Directory.GetFiles Method (String, String)中有解释。

由于此方法检查具有8.3文件名格式和长文件名格式的文件名,类似于“1.txt”的搜索模式可能会返回意外的文件名。例如,使用搜索模式“1.txt”将返回“longfilename.txt”,因为等效的8.3文件名格式为“longf~1.txt”。

解决方法:您可以使用Directory.EnumerateFiles先选择符合条件的两个文件,然后使用StartsWith比较实际(长)文件名部分。请记住EnumerateFiles进行惰性评估。
String[] search1 = Directory.EnumerateFiles(@"C:\test", "85267-*.wav")
                         .Where(file => Path.GetFileName(file).StartsWith("85267-"))
                         .Select(path => Path.GetFileName(path))
                         .ToArray();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接