16

I have a directory with multiple sub directories that contain .doc files. Example:

C:\Users\user\Documents\testenviroment\Released\test0.doc
C:\Users\user\Documents\testenviroment\Debug\test1.doc
C:\Users\user\Documents1\testenviroment\Debug\test2.doc
C:\Users\user\Documents1\testenviroment\Released\test20.doc

I want to get all the test*.doc files under all Debug folders. I tried:

string[] files = Directory.GetFiles(@"C:\Users\user", "*Debug\\test*.doc",
    SearchOption.AllDirectories);

And it gives me an "Illegal characters in path" error.

If I try:

string[] files = Directory.GetFiles(@"C:\Users\user", "\\Debug\\test*.doc",
    SearchOption.AllDirectories); 

I get a different error: "Could not find a part of the path C:\Users\user\Debug".

Boann
  • 48,794
  • 16
  • 117
  • 146
Me5
  • 1,705
  • 3
  • 13
  • 19
  • 3
    If the path is like `C:\Users\user\Documents` why are you searching in `C:\Users\user\Debug`? – Pikoh Mar 01 '17 at 12:07
  • 2
    @HimBromBeere: Yes you can. Acc. to MSDN `The search string to match against the names of files in path. This parameter can contain a combination of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions.` https://msdn.microsoft.com/en-us/library/ms143316(v=vs.110).aspx – Nikhil Agrawal Mar 01 '17 at 12:10
  • There are certainly illegal characters in your path. Nothing is wrong with your search string/ – Chibueze Opata Mar 01 '17 at 12:14
  • My bad. Yes, actually didn't look well enough. The wildcard is correct which is what makes the problem interesting at first sight. – Chibueze Opata Mar 01 '17 at 12:51

2 Answers2

13

You are including a folder within the search pattern which isn't expected. According to the docs:

searchPattern Type: System.String The search string to match against the names of files in path. This parameter can contain a combination of valid literal path and wildcard (* and ?) characters (see Remarks), but doesn't support regular expressions.

With this in mind, try something like this:

String[] files = Directory.GetFiles(@"C:\Users\user", "test*.doc", SearchOption.AllDirectories)
                 .Where(file => file.Contains("\\Debug\\"))
                 .ToArray();

This will get ALL the files in your specified directory and return the ones with Debug in the path. With this in mind, try and keep the search directory narrowed down as much as possible.

Note:

My original answer included EnumerateFiles which would work like this (making sure to pass the search option (thanks @CodeCaster)):

String[] files = Directory.EnumerateFiles(@"C:\Users\user", "test*.doc", SearchOption.AllDirectories)
                 .Where(file => file.Contains("\\Debug\\"))
                 .ToArray();

I've just run a test and the second seems to be slower however it might be quicker on a larger folder. Worth keeping in mind.

Edit: Note from @pinkfloydx33

I've actually had that practically take down a system that I had inherited. It was taking so much time trying to return the array and killing the memory footprint as well. Problem was diverted converting over to the enumerable counterparts

So using the second option would be safer for larger directories.

webnoob
  • 15,747
  • 13
  • 83
  • 165
  • Possibly better to use DirectoryInfo.EnumerateFiles to make use of the enumerable-ness of the return value. Otherwise all results are returned up front which can cause issues on directories with large number of files – pinkfloydx33 Mar 01 '17 at 12:39
  • @pinkfloydx33 Was adding an example with that in mind as you commented :) – webnoob Mar 01 '17 at 12:40
  • 1
    I've actually had that practically take down a system that I had inherited. It was taking so much time trying to return the array and killing the memory footprint as well. Problem was diverted converting over to the enumerable counterparts. – pinkfloydx33 Mar 01 '17 at 12:42
  • 1
    @pinkfloydx33 Thanks, good to know. I've added that comment to the answer so people are clear about which option to use. – webnoob Mar 01 '17 at 12:44
  • Though the folders had file counts several orders of magnitude larger than what you would expect from a "typical" folder. Switching to enumerable also benefits when you add the Where extension method like you did and should prevent iterating the files twice (once to get, second for where) – pinkfloydx33 Mar 01 '17 at 12:45
  • "user" appears to be a placeholder for the actual account name. Just hope that the username isn't "Debug" - it is not beyond the realms of possibility. – Andrew Morton Mar 01 '17 at 13:29
  • I'd imagine the second is more memory-efficient, but has to do a filesystem query every time, so it's slower, while the other... well, it definitely at least does it all at once, then stores the results in a List. I dunno if that'd speed it up. Which you use depends on what you need. – Nic Mar 01 '17 at 14:29
  • @QPaysTaxes I agree which is why I left both examples there. It really depends on the use case I think. – webnoob Mar 01 '17 at 14:31
2

The second parameter, the search pattern, works only for filenames. So you'll need to iterate the directories you want to search, then call Directory.GetFiles(directory, "test*.doc") on each directory.

How to write that code depends on how robust you want it to be and what assumptions you want to make (e.g. "all Debug directories are always two levels into the user's directory" versus "the Debug directory can be at any level into the user's directory").

See How to recursively list all the files in a directory in C#?.

Alternatively, if you want to search all subdirectories and then discard files that don't match your preferences, see Searching for file in directories recursively:

var files = Directory.GetFiles(@"C:\Users\user", "test*.doc", SearchOption.AllDirectories)
               .Where(f => f.IndexOf(@"\debug", StringComparison.OrdinalIgnoreCase) >= 0);

But note that this may be bad for performance, as it'll scan irrelevant directories.

Community
  • 1
  • 1
CodeCaster
  • 147,647
  • 23
  • 218
  • 272