5

I'm trying to list out all files under a given directory by taking sub directories as well into account.I'm using yield so that I could club this with Take where I call this (note that I'm using .NET 3.5).

Below is my code:

IEnumerable<string> Search(string sDir)
{
       foreach (var file in Directory.GetFiles(sDir))
       {
            yield return file;                
       }

       foreach (var directory in Directory.GetDirectories(sDir))
       {
                Search(directory);                
       }
}

I don't know what is going wrong here, but it only returns one file (which is the one under the root directory, and there is only one there as well). Can you please help?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Mike
  • 3,204
  • 8
  • 47
  • 74
  • 12
    Don't reinvent the wheel. Use `Directory.EnumerateFiles` and `Directory.EnumerateDirectories`. – Oded May 17 '13 at 12:00
  • Oh, and you are not `yield return`ing the `Search(directory)`, which is probably one of the issues here. – Oded May 17 '13 at 12:00
  • Thanks Oded..will Directory.EnumerateFiles and Directory.EnumerateDirectories work in .NEt 3.5? – Mike May 17 '13 at 12:04
  • 4
    @Oded *"Note that I'm using .Net 3.5"* .. which doesn't have `EnumerateDirectories` – Matthew Watson May 17 '13 at 12:04
  • 1
    If you're curious as to the differences between `Directory.EnumerateFiles` and `Directory.GetFiles`, see here: http://stackoverflow.com/questions/5669617/what-is-the-difference-between-directory-enumeratefiles-vs-directory-getfiles – John H May 17 '13 at 12:04
  • ...But .Net 3.5 *does* have `GetFiles(string,string,SearchOption)` – Matthew Watson May 17 '13 at 12:09
  • @MatthewWatson: As mentioned below (and linked above), calling `GetFiles(string, string, SearchOption.AllDirectories)` (which is what I'm assuming you're referring to) is evaluated eagerly which could have significant implications for performance/memory, especially if the intent is to search until certain criteria are met. The implementation Mike is creating is deferred. (EDIT: Well, still eager within _each_ directory, but that will likely not have as large an impact unless a single directory has thousands of files) – Chris Sinclair May 17 '13 at 12:11
  • @ChrisSinclair I agree, which is why my comment to your answer says that I like it better. :) (Looking at my comment, I guess it wasn't totally clear that `it` referred to your answer rather than the .Net GetFiles() method...) – Matthew Watson May 17 '13 at 12:22

1 Answers1

12

You need to yield the results of the recursive search, otherwise you're just throwing its results away:

IEnumerable<string> Search(string sDir)
{
    foreach (var file in Directory.GetFiles(sDir))
    {
        yield return file;                
    }

    foreach (var directory in Directory.GetDirectories(sDir))
    {
        foreach(var file in Search(directory))
            yield return file;
    }
}

Note that if your intent is to simply get a flat list of every file, consider using Directory.GetFiles instead with the option to search all subdirectories. If your intent is to leverage LINQ (or other methods) to apply searching criteria or a limit to the total number of files retrieved, then this is a decent way to go as you'll read directories one at a time and stop once you've fulfilled your criterion.

Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93
  • 6
    Wouldn't [Directory.GetFiles(String, String, SearchOption)](http://msdn.microsoft.com/en-us/library/ms143316.aspx) be more appropriate? – John H May 17 '13 at 12:06
  • Encoding with the pinnacle of technology. – lsalamon May 17 '13 at 12:07
  • In some respects, writing your own version of this is handy even on .Net 4 or later - because the .Net 4 version doesn't have any easy way of handling exceptions due to inaccessible system folders. At least if you roll-your-own, you can add proper handling. However, .Net 3.5 *does* have `Directory.GetFiles(string,string,SearchOption)` as John H says! But I like this better. – Matthew Watson May 17 '13 at 12:07
  • @JohnH Probably, falls under the "don't reinvent the wheel" comment. I was answering Mike's question specifically about why his implementation was not working. Also note that `Directory.GetFiles` is evaluated _eagerly_ which could take a long time or a lot of memory depending on its usage whereas this implementation is deferred. – Chris Sinclair May 17 '13 at 12:07
  • Fair enough. I linked to a question which describes the implementation details, above. – John H May 17 '13 at 12:08