views:

69

answers:

3

In C#, how do I check if a specific file exists in a directory or any of its subdirectories?

System.IO.File.Exists only seems to accept a single parameter with no overloads to search subdirectories.

I can do it with LINQ and System.IO.Directory.GetFiles using the SearchOption.AllDirectories overload, but that seems a bit heavy handed.

 var MyList = from f in Directory.GetFiles(tempScanStorage, "foo.txt", SearchOption.AllDirectories)
              where System.IO.Path.GetFileName(f).ToUpper().Contains(foo)
              select f;

      foreach (var x in MyList)
      {
          returnVal = x.ToString();
      }  
+3  A: 

If you're looking for a single specific filename, using *.* is indeed heavy handed. Try this:

var file = Directory.GetFiles(tempScanStorage, foo, SearchOption.AllDirectories)
                    .FirstOrDefault();
if (file == null)
{
    // Handle the file not being found
}
else
{
    // The file variable has the *first* occurrence of that filename
}

Note that this isn't quite what your current query does - because your current query would find "xbary.txt" if you foo was just bar. I don't know whether that's intentional or not.

If you want to know about multiple matches, you shouldn't use FirstOrDefault() of course. It's not clear exactly what you're trying to do, which makes it hard to give more concrete advice.

Note that in .NET 4 there's also Directory.EnumerateFiles which may or may not perform better for you. I highly doubt that it'll make a difference when you're searching for a specific file (instead of all files in the directory and subdirectories) but it's worth at least knowing about.

Jon Skeet
@Jon: Yes, I am looking to find a single specific file. I've updated the '*.*'. Thanks for the tight solution.
David HAust
A: 

It is a recursive search on the filesystem. You have some functional examples in CodeProject:

caligari
A: 

The alternative is to write the search function yourself, one of these should work:

    private bool FileExists(string rootpath, string filename)
    {
        if(File.Exists(Path.Combine(rootpath, filename)))
            return true;

        foreach(string subDir in Directory.GetDirectories(rootpath, "*", SearchOption.AllDirectories))
        {
            if(File.Exists(Path.Combine(rootpath, filename)))
            return true;
        }

        return false;
    }

    private bool FileExistsRecursive(string rootPath, string filename)
    {
        if(File.Exists(Path.Combine(rootPath, filename)))
            return true;

        foreach (string subDir in Directory.GetDirectories(rootPath))
        {
            return FileExistsRecursive(subDir, filename);
        }

        return false;
    }

The first still pulls out all of the directory names first so could be slow if there are lots of subdirectories and the file is close to the top.

The second is recursive, may be slower in 'worst case' scenarios but would be faster if there are many nested subdir and the file is in a top level dir.

ach