2

I'm trying to get all files that start with a specific name (case insensitive).

Directory.GetFiles seems to be case sensitive on OSX (but not on Windows) so I'm wondering what are my options. The directory can be potentially big so getting all files and filtering in memory is probably not the greatest idea.

I'm using Unity which has a pre 4.0 mono runtime so can't use EnumerateFiles.

Any workarounds?

radu
  • 606
  • 7
  • 17
  • possible duplicate of [Can you call Directory.GetFiles() with multiple filters?](http://stackoverflow.com/questions/163162/can-you-call-directory-getfiles-with-multiple-filters) – Peter Duniho Jan 20 '15 at 23:37
  • 1
    No, please read the question carefully. If I'm searching for something like blahblah* I would have to have all case permutations (2^x) of that to catch all files. – radu Jan 20 '15 at 23:45
  • No, please read the duplicate answer carefully. The key is to use `Directory.EnumerateFiles()`, retrieving _all_ files from the directory, but in an efficient way (i.e. you don't need one big array of file names in memory all at once). As you enumerate the file names, you can apply whatever filtering criteria you want, including a simple `string.StartsWith()` or a full-blown `Regex.Match()` operation. Since `StartsWith()` allows case-insensitive searches, you only need to examine each file name once. – Peter Duniho Jan 20 '15 at 23:50
  • I had read the question you're pointing to before posting this question. Unfortunately EnumerateFiles is 4.0 and above (using Unity which is definitely not using the 4.0 mono runtime). – radu Jan 20 '15 at 23:55
  • Ah. Well, your options are somewhat limited then. You can either implement `EnumerateFiles()` yourself (assuming Mono supports some kind of p/invoke to access the platform-specific file enumeration functionality), or you can get the file names in batches, by e.g. using "a*", "A*", "b*", "B*", etc. as your search pattern. Or, you can just go ahead and use `Directory.GetFiles()` and see what happens. Maybe it wouldn't be the best idea, but it's probably not the worst either. – Peter Duniho Jan 21 '15 at 00:00
  • In any case, you should edit your question to clarify why you don't want to/can't use `Directory.EnumerateFiles()`. – Peter Duniho Jan 21 '15 at 00:01
  • Can you move your previous comment (the one with "somewhat limited") to an answer so I can accept it? – radu Jan 21 '15 at 02:44
  • I did edit the answer I already posted, to include the information I added in that comment...is there something about the answer as a whole that you feel still doesn't meet your needs? – Peter Duniho Jan 21 '15 at 03:07

1 Answers1

0

IMHO, the linked question I propose as a duplicate should suffice. But in the interest of completeness and clarity, here is what I mean you to do:

IEnumerable<string> EnumerateSpecificFiles(
    string directory, string initialTextForFileName)
{
    foreach (string file in Directory.EnumerateFiles(directory))
    {
        if (file.StartsWith(initialTextForFileName, StringComparison.OrdinalIgnoreCase))
        {
            yield return file;
        }
    }
}

This avoids having the entire list of file names in memory, while still allowing you to perform your case-insensitive search.


EDIT:

Given that it turns out you are using an earlier version of Mono, which does not include the Directory.EnumerateFiles() method, your next best option is to go ahead and implement that method yourself using p/invoke (perhaps even just copy the implementation from the current Mono sources).

As a hack, you could at least restrict the number of files returned by Directory.GetFiles() by applying a partial filter. E.g.:

IEnumerable<string> EnumerateSpecificFiles(
    string directory, string initialTextForFileName)
{
    char[] initialCharacters =
        {
            char.ToLowerInvariant(initialTextForFileName[0]),
            char.ToUpperInvariant(initialTextForFileName[0])
        };

    foreach (char ch in initialCharacters)
    {
        foreach (string file in Directory.GetFiles(directory, ch + "*"))
        {
            if (file.StartsWith(initialTextForFileName, StringComparison.OrdinalIgnoreCase))
            {
                yield return file;
            }
        }
    }
}

Finally, you may consider just getting all the files in the directory all at once using the Directory.GetFiles() method and filtering that result as above. You may find it works well enough.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136