我需要列出目录中与某些模式匹配的文件。我尝试过与一起玩Directory.GetFiles,但还不完全了解为什么它会以某种方式运行。
1)例如,此代码:
string[] dirs = Directory.GetFiles(@"c:\test\", "*t");
foreach (string dir in dirs)
{
Debugger.Log(0, "", dir);
Debugger.Log(0, "", "\n");
}
Run Code Online (Sandbox Code Playgroud)
输出此:
c:\test\11.11.2007.txtGif
c:\test\12.1.1990.txt
c:\test\2.tGift
c:\test\2.txtGif
c:\test\test.txt
...others hidden
Run Code Online (Sandbox Code Playgroud)
您可以看到一些文件以结尾f但仍由查询返回,为什么?
2)另外,
string[] dirs = Directory.GetFiles(@"c:\test\", "*.*.*.txt");
foreach (string dir in dirs)
{
Debugger.Log(0, "", dir);
Debugger.Log(0, "", "\n");
}
Run Code Online (Sandbox Code Playgroud)
返回此:
c:\test\1.1.1990.txt
c:\test\1.31.1990.txt
c:\test\12.1.1990.txt
c:\test\12.31.1990.txt
Run Code Online (Sandbox Code Playgroud)
但是根据文档(http://msdn.microsoft.com/zh-cn/library/07wt70x2(v=vs.110).aspx),我认为它还必须返回目录中的该文件:
11.11.2007.txtGif
Run Code Online (Sandbox Code Playgroud)
由于扩展名(在查询字符串中)的长度为3个字母, 但没有。为什么?(当查询扩展名的长度为3个字母时,doc会说它也会返回以指定扩展名开头的扩展名,例如,请参见“备注”。)
我是唯一发现这些结果奇怪的人吗?
当有人想要列出文件夹中符合特定格式的文件时,还有其他建议使用的方法吗?
在我的情况下,用户可以任意键入某种模式,并且我不想依赖我不确定结果的方法(例如GetFiles发生的情况)。
所有这些行为都与您链接的文档中描述的完全相同。以下是相关部分的摘录:
当您在 searchPattern 中使用星号通配符(例如“*.txt”)时,指定扩展名中的字符数会影响搜索,如下所示:
如果指定的扩展名恰好是三个字符长,则该方法返回扩展名以指定扩展名开头的文件。例如,“*.xls”同时返回“book.xls”和“book.xlsx”。
在所有其他情况下,该方法返回与指定扩展名完全匹配的文件。例如,“*.ai”返回“file.ai”,但不返回“file.aif”。
当您使用问号通配符时,此方法仅返回与指定文件扩展名匹配的文件。例如,给定目录中的两个文件“file1.txt”和“file1.txtother”,搜索模式“file?.txt”仅返回第一个文件,而搜索模式“file*.txt”返回两个文件。注释注释
由于此方法会检查同时具有 8.3 文件名格式和长文件名格式的文件名,因此类似于“ 1.txt ”的搜索模式可能会返回意外的文件名。例如,使用搜索模式“ 1 .txt”将返回“longfilename.txt”,因为等效的 8.3 文件名格式为“LONGFI~1.TXT”。
http://msdn.microsoft.com/en-us/library/wz42302f%28v=vs.110%29.aspx
上面的最后一段清楚地解释了搜索时的结果*t。您可以通过使用命令dir C:\test /x显示 8.3 文件名来看到这一点。在这里,C:\test\11.11.2007.txtGif匹配是*t因为它的 8.3 文件名是111120~1.TXT.
对于 的处理*.*.*.txt,我认为您要么误解了有关三字母文件扩展名的第一部分,要么可能写得不太清楚。请注意,他们非常明确地提到了“在搜索模式中使用通配符,例如“*.txt””。您的搜索模式与此不匹配,因此您必须仔细阅读字里行间,以了解为什么他们关于三字母文件扩展名的评论适用于他们给出的示例,但不适用于您的示例。确实,我认为如果您只是对 8.3 文件名的最后一点进行一些思考,那么整个顶部部分都可以忽略。通配符后对三字母文件扩展名的处理实际上只是 8.3 文件名搜索行为的副作用。
考虑一下他们给出的例子:
“*.xls”同时返回“book.xls”和“book.xlsx”
这是因为“book.xls”的文件名(8.3 和长文件名,因为该名称自然符合 8.3)和“book.xlsx”的 8.3 文件名(“BOOK~1.XLS”)与“ *.xls”。
“*.ai”返回“file.ai”,但不返回“file.aif”
这是因为“file.ai”自然会匹配“*.ai”,而“file.aif”则不会。8.3 搜索行为在这里根本不起作用,因为两个文件名都已经符合 8.3 标准。然而,即使不是,同样的情况仍然成立,因为扩展名为“.ai”的文件的任何 8.3 文件名仍然以“.AI”结尾。
搜索中的文件扩展名是否恰好是三个字符很重要的唯一原因是因为 8.3 文件名包含在搜索中,并且长文件名对象的 8.3 文件名扩展名始终只包含最后一个点之后的前三个字符在长文件名中。上面的文档中缺少的关键部分是“前三个字符”匹配仅针对 8.3 文件名进行。
那么,让我们看看您在这里询问的异常情况。*.t(如果您想要解释除和 的结果之外的任何其他奇怪行为*.*.*.txt,请将它们作为单独的问题发布。)
搜索的输出*t包括11.11.2007.txtGif和2.txtGif。
这是因为 8.3 文件名与*t.
11.11.2007.txtGif= 111120~1.TXT
2.txtGIF=2BEFD~1.TXT
(两个 8.3 文件名均以“T”结尾。)
搜索的输出*.*.*.txt不包括11.11.2007.txtGif.
这是因为长文件名和 8.3 文件名都不匹配*.*.*.txt.
11.11.2007.txtGif=111120~1.TXT
(长文件名不匹配,因为它不以“.txt”结尾,8.3 文件名不匹配,因为它只有一个点。)
这就是Windows API的工作方式-如果dir在命令提示符下使用该命令,您将看到相同的结果。这不使用正则表达式!相当晦涩...
如果要自己过滤,可以这样:
var filesEndingInT = Directory.EnumerateFiles(@"c:\test\").Where(f => f.EndsWith("t"));
Run Code Online (Sandbox Code Playgroud)
如果要使用正则表达式进行匹配,则可以这样进行:
Regex regex = new Regex(".*t$");
var matches = Directory.EnumerateFiles(@"c:\test\").Where(f => regex.IsMatch(f));
Run Code Online (Sandbox Code Playgroud)
我怀疑您希望让用户以简化形式的模式输入并将其转换为正则表达式,例如
"*.t" -> ".*t$"
Run Code Online (Sandbox Code Playgroud)
查找所有以t结尾的文件名的正则表达式为“。* t $”:
.*t$
Run Code Online (Sandbox Code Playgroud)
