2011-03-10 101 views
6

作为一个简单的例子,我执行以下c#EnumerateFiles通配符返回非匹配?

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

在我的结果集我正在里面做不匹配文件模式的几个文件。根据msdn searchPattern通配符是“零个或多个字符”而不是注册前。一个例子就是我将文件名恢复为“2004_someothername.xml”。

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

有没有人有任何想法是怎么回事?

+1

你可以发布一些不匹配的文件名的例子吗? – cptScarlet 2011-03-10 15:52:05

+0

你说“作为一个简单的例子” - 你是否测试过你显示的代码实际上会返回你声明的文件?这个问题更可能是由非简化的例子引起的......! – 2011-03-10 15:53:06

+0

您提供的示例正常工作。刚刚测试过它。所以,如果你可以请张贴实际的代码不能正常工作 – Stecya 2011-03-10 15:56:48

回答

8

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

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

总之,是非常小心,特别是如果你有很多文件上作出任何重要的生产决策或采取基于一个OS文件/通配符匹配任何行动的目录,没有结果的二次验证。

这是一个explanation这种奇怪的行为。

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

+2

小心链接到错误报告? – 2011-03-10 16:12:29

+3

你有没有参考该错误?我无法使用system.IO.Directory类在PowerShell中使用50,000个文件重新创建它。 – 2011-03-10 16:13:11

+0

@所有的事情,在对这个原因做进一步研究之后,我更新了我的答案,并解释了问题和参考资料。 – 2011-03-10 17:57:38

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; 
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] 

您能否在真实应用程序中提供更多关于您的场景中发生的情况的反馈?或者你可以在较小的应用程序中重现问题?

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 
+1

尽管它是VB,为了大功夫+1! :) – 2011-03-10 16:51:41

+2

因为所有的C#人都用C#来回答VB的问题,所以我认为我会做相反的事情!其实,这正是我目前打开的。 – 2011-03-10 17:02:41

0

在遭受了同样的问题,并发现这个职位,我想我会后我的解决方案:

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

这只是测试后缀,但消除的比赛到结束的.xml〜我的备份文件。