【问题标题】:List files in folder which match pattern列出文件夹中匹配模式的文件
【发布时间】:2014-11-02 14:07:00
【问题描述】:

我需要列出目录中匹配某种模式的文件。 我试过玩Directory.GetFiles,但不完全 了解为什么它会以某种方式运行。

1) 例如这段代码:

            string[] dirs = Directory.GetFiles(@"c:\test\", "*t");

            foreach (string dir in dirs)
            {
                Debugger.Log(0, "", dir);
                Debugger.Log(0, "", "\n");

            }

输出这个:

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

您可以看到一些文件以f 结尾,但仍被查询返回,为什么

2) 还有,这个:

                string[] dirs = Directory.GetFiles(@"c:\test\", "*.*.*.txt");


                foreach (string dir in dirs)
                {
                    Debugger.Log(0, "", dir);
                    Debugger.Log(0, "", "\n");

                }

返回这个:

c:\test\1.1.1990.txt
c:\test\1.31.1990.txt
c:\test\12.1.1990.txt
c:\test\12.31.1990.txt

但是根据文档 (http://msdn.microsoft.com/en-us/library/07wt70x2(v=vs.110).aspx) 我认为它也必须返回 目录中的这个文件:

11.11.2007.txtGif

因为扩展名(在查询字符串中)是 3 个字母长, 但它没有。为什么? (当查询扩展名长度为 3 个字母时,doc 表示它也会返回以指定扩展名开头的扩展名,例如,请参阅备注)。


只有我觉得这些结果很奇怪吗?

当您想要列出文件夹中与特定模式匹配的文件时,您是否推荐使用其他方法?

在我的情况下,用户可能会随意输入一些模式,我不想依赖 我不确定结果的方法(就像 GetFiles 发生的那样)。

【问题讨论】:

  • 扩展名是txtGif,而不仅仅是txt。
  • 第一个例子我觉得很奇怪,但后来我也觉得难以置信。 (我并不怀疑你,它为什么会返回 f 是没有意义的)(也许 *.*t 可能会有所帮助)
  • 已经试过了吗? Directory.GetFiles(@"c:\test\", "\w*.txt");

标签: c# .net directory


【解决方案1】:

https://docs.microsoft.com/en-us/dotnet/api/system.io.directoryinfo.getfiles?view=netframework-4.5

上面的微软文档和往常一样是错误的, 它说这个代码:

            DirectoryInfo di = new DirectoryInfo(@"C:\Users\tomfitz\Documents\ExampleDir");
            Console.WriteLine("No search pattern returns:");

            Console.WriteLine();

            Console.WriteLine("Search pattern *2* returns:");
            foreach (var fi in di.GetFiles("*2*"))
            {
                Console.WriteLine(fi.Name);
                Console.WriteLine(fi.Fullname); // this reveals the bug
            }

应该返回以下但它没有

它仍然匹配整个文件路径,而不仅仅是文件名。

Search pattern *2* returns:
log2.txt
test2.txt

【讨论】:

    【解决方案2】:

    所有这些行为都与您链接的文档中的描述完全相同。以下是相关部分的摘录:

    当您在 searchPattern 中使用星号通配符时 如“*.txt”,指定扩展名中的字符数 对搜索的影响如下:

    • 如果指定的扩展名恰好是三个字符长,则该方法返回扩展名以指定开头的文件 延期。例如,“*.xls”返回“book.xls”和 “book.xlsx”。

    • 在所有其他情况下,该方法返回与指定扩展名完全匹配的文件。例如,“*.ai”返回“file.ai”,但不返回 “文件.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 标准。然而,即使它们不是,同样的情况仍然适用,因为任何 8.3 文件名的扩展名为“.ai”的文件仍将仅以“.AI”结尾。

    搜索中的文件扩展名是否恰好是三个字符重要的唯一原因是搜索中包含 8.3 文件名,长文件名对象的 8.3 文件名扩展名将始终在长文件名的最后一个点之后只有前三个字符。上述文档中缺少的关键部分是“前三个字符”匹配针对 8.3 文件名。

    那么,让我们看看您在这里询问的异常情况。 (如果您想解释任何其他奇怪的行为,除了 *.t*.*.*.txt 的结果,请将它们作为单独的问题发布。)


    TL;DR:

    搜索*t 的输出包括11.11.2007.txtGif2.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 文件名不匹配,因为它只有一个点。)

    【讨论】:

      【解决方案3】:

      这是 Windows API 的工作方式 - 如果您在命令提示符中使用 dir 命令,您将看到相同的结果。这不使用正则表达式!好难懂……

      如果你想做自己的过滤,你可以这样做:

      var filesEndingInT = Directory.EnumerateFiles(@"c:\test\").Where(f => f.EndsWith("t"));
      

      如果你想使用正则表达式匹配,你可以这样做:

      Regex regex = new Regex(".*t$");
      var matches = Directory.EnumerateFiles(@"c:\test\").Where(f => regex.IsMatch(f));
      

      我怀疑你会想让用户输入一个简化形式的模式并将其转换为正则表达式,例如

      "*.t" -> ".*t$"
      

      查找所有以 t 结尾的文件名的正则表达式是“.*t$”:

      .*t$
      

      Debuggex Demo

      【讨论】: