c#EnumerateFiles通配符返回非匹配?

时间:2011-03-10 15:41:01

标签: c# .net

作为简化示例,我正在执行以下

IEnumerable<string> files = Directory.EnumerateFiles(path, @"2010*.xml", 
    SearchOption.TopDirectoryOnly).ToList();

在我的结果集中,我得到一些与文件模式不匹配的文件。根据msdn searchPattern通配符是“零个或多个字符”而不是reg ex。一个例子是我得到的文件名为“2004_someothername.xml”。

有关信息,文件夹中有超过25,000个文件。

有谁知道发生了什么事?

5 个答案:

答案 0 :(得分:8)

这是由于Windows如何进行通配符匹配 - 它在其通配符搜索中包含编码的8.3文件名,导致一些令人惊讶的匹配!

解决此错误的一种方法是重新测试通过OS通配符匹配返回的所有文件结果,并通过手动比较通配符与每个(长)文件名进行测试。另一种方法是turn off 8.3 filenames altogether via the registry。我已经在很多场合被烧毁了,包括从命令提示符中通过基于通配符的del命令删除重要的(不匹配的)文件。

总而言之,非常小心,特别是如果您在制作任何关键生产决策的目录中有许多文件或根据操作系统文件/通配符匹配执行任何操作,而无需进行二次验证结果

以下是这种离奇行为的explanation

O'Reilly's site的另一个解释。

答案 1 :(得分:2)

我可以使用以下代码重现您的问题(抱歉,VB)。它创建了55,000个名为2000_0001.xml2010_5000.xml的零字节文件。然后它会查找以2010开头的所有文件。在我的机器上(Windows 7 SP1 32位),它返回5,174个文件而不是5,000个。

Option Explicit On
Option Strict On

Imports System.IO

Public Class Form1

    Private TempFolder As String = Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "Temp")

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        CreateFiles()

        Dim Files = Directory.EnumerateFiles(TempFolder, "2010*.xml", SearchOption.TopDirectoryOnly).ToList()
        Using FS As New FileStream(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "Report.txt"), FileMode.Create, FileAccess.Write, FileShare.Read)
            Using SW As New StreamWriter(FS, System.Text.Encoding.ASCII)
                For Each F In Files
                    SW.WriteLine(F)
                Next
            End Using
        End Using


        DeleteFiles()
    End Sub

    Private Sub CreateFiles()
        If Not Directory.Exists(TempFolder) Then Directory.CreateDirectory(TempFolder)
        Dim Bytes() As Byte = {}
        Dim Name As String
        For Y = 2000 To 2010
            Trace.WriteLine(Y)
            For I = 1 To 5000
                Name = String.Format("{0}_{1}.xml", Y, I.ToString.PadLeft(4, "0"c))
                File.WriteAllBytes(Path.Combine(TempFolder, Name), Bytes)
            Next
        Next
    End Sub
    Private Sub DeleteFiles()
        Directory.Delete(TempFolder, True)
    End Sub
End Class

答案 2 :(得分:1)

不是MS错误的解决方案(可能使用下面的Windows文件搜索,这对您的结果来说太糟糕了......),但作为解决方案的解决方案,它为您提供了一些额外的杠杆和对结果的控制:

var files = from file in 
      Directory.EnumerateFiles(path, "*",
      SearchOption.TopDirectoryOnly)
      where (new FileInfo(file)).Name.StartsWith("2010") &&
          (new FileInfo(file)).Extension == "xml"
      select dir;

答案 3 :(得分:1)

我刚试过你的例子而且我看不出它做错了什么,所以我想你的环境和/或这里没有涉及的“非简化”代码还有更多。

我用过这段代码:

Console.WriteLine("Starting...");
IEnumerable<string> files = Directory.EnumerateFiles("C:\\temp\\test\\2010", @"2010*.xml", SearchOption.TopDirectoryOnly).ToList();

foreach (string file in files)
{
    Console.WriteLine("Found[{0}]", file);
}

Console.ReadLine();

在我的文件夹结构中,我创建了以下内容:

C:\ TEMP \测试\ 2010 \ 2004_something.xml C:\ TEMP \测试\ 2010 \ 2010_abc.xml C:\ TEMP \测试\ 2010 \ 2010_def.xml

应用程序的输出只是:

Starting...
Found[C:\temp\test\2010\2010_abc.xml]
Found[C:\temp\test\2010\2010_def.xml]

您是否可以在真实应用中提供有关您的方案中发生的事情的更多反馈?或者你可以在较小的应用程序中重现问题吗?

答案 4 :(得分:0)

遇到同样的问题,找到这篇文章,我想我会发布我的解决方案:

IEnumerable<string> Files = Directory.EnumerateFiles(e.FileName, "*.xml").Where(File => File.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase));

这只会测试后缀,但会删除与我的备份文件匹配的内容.xml~。