Как заставить GetFiles() исключать файлы с расширениями, начинающимися с расширения поиска?

Я использую следующую строку для возврата определенных файлов...

FileInfo file in nodeDirInfo.GetFiles("*.sbs", option)

Но в каталоге есть и другие файлы с расширением .sbsar, и он их тоже получает. Как отличить .sbs от .sbsar в шаблоне поиска?


person topofsteel    schedule 27.11.2013    source источник
comment
Вы не можете (по крайней мере, с GetFiles/GetDirectories). Это ограничение шаблона поиска. Вы должны перебирать результаты и вручную фильтровать те, которые вы хотите.   -  person varocarbas    schedule 27.11.2013
comment
также взгляните на это: msdn.microsoft. com/en-us/library/wz42302f(v=vs.110).aspx   -  person Ahmed ilyas    schedule 27.11.2013


Ответы (4)


Попробуйте это, отфильтровано с использованием расширения файла.

  FileInfo[] files = nodeDirInfo.GetFiles("*", SearchOption.TopDirectoryOnly).
            Where(f=>f.Extension==".sbs").ToArray<FileInfo>();
person Sid    schedule 27.11.2013

Проблема, с которой вы столкнулись, связана с ограничением шаблона поиска в Win32 API.

SearchPattern с расширением файла (например, *.txt) ровно из трех символов возвращает файлы с расширением из трех или более символов, где первые три символа соответствуют расширению файла, указанному в searchPattern.

Мое решение состоит в том, чтобы вручную отфильтровать результаты с помощью Linq:

nodeDirInfo.GetFiles("*.sbs", option).Where(s => s.EndsWith(".sbs"),
    StringComparison.InvariantCultureIgnoreCase));
person Daniel Peñalba    schedule 27.11.2013
comment
Здесь не учитывается регистр букв. - person David Heffernan; 27.11.2013

Это поведение Win32 API (FindFirstFile), которое находится под GetFiles(), отражается на вас.

Вам нужно будет сделать свою собственную фильтрацию, если вы должны использовать GetFiles(). Например:

GetFiles("*", searchOption).Where(s => s.EndsWith(".sbs", 
    StringComparison.InvariantCultureIgnoreCase));

Или более эффективно:

EnumerateFiles("*", searchOption).Where(s => s.EndsWith(".sbs", 
    StringComparison.InvariantCultureIgnoreCase));

Обратите внимание, что я использую StringComparison.InvariantCultureIgnoreCase, чтобы иметь дело с тем фактом, что имена файлов Windows нечувствительны к регистру.

Если производительность является проблемой, то есть если поиск должен обрабатывать каталоги с большим количеством файлов, то более эффективно выполнять фильтрацию дважды: один раз при вызове GetFiles или EnumerateFiles и один раз для очистки нежелательных имен файлов. . Например:

GetFiles("*.sbs", searchOption).Where(s => s.EndsWith(".sbs", 
    StringComparison.InvariantCultureIgnoreCase));
EnumerateFiles("*.sbs", searchOption).Where(s => s.EndsWith(".sbs", 
    StringComparison.InvariantCultureIgnoreCase));
person David Heffernan    schedule 27.11.2013
comment
@Joey Джоуи Просто мне кажется, что это немного грязно, дублируя фильтр. Но, возможно, это имело бы значение производительности. Если нет, то я предпочел бы иметь только один фильтр. - person David Heffernan; 27.11.2013
comment
Это быстрее, однако ;-) В моем небольшом тесте здесь (пробежка по нашей полной исходной папке, поиск *.cpp) примерно на 10–25 % быстрее указать фильтр и в GetFiles. EnumerateFiles немного медленнее, но, вероятно, использует гораздо меньше памяти, особенно для больших наборов результатов. - person Joey; 27.11.2013
comment
@Джоуи Да, я думаю, это разумно. Я думаю, все сводится к балансу между производительностью и чистотой! Я рассказал об этом в ответе сейчас. - person David Heffernan; 27.11.2013
comment
О, и я думаю, что .EndsWith(".sbs", StringComparison.InvariantCultureIgnoreCase) был бы лучшим вариантом, который также устойчив к культуре, поскольку файловая система игнорирует культуру из-за ее нечувствительности к регистру. - person Joey; 27.11.2013
comment
@Джоуи, спасибо. Показываю свое невежество с ToLower()! - person David Heffernan; 27.11.2013

Упоминается в документах.

При использовании подстановочного знака звездочки в searchPattern searchPattern с расширением файла ровно из трех символов возвращает файлы с расширением из трех или более символов. При использовании подстановочного знака вопросительного знака этот метод возвращает только файлы, соответствующие указанному расширению файла. .

person Anirudha    schedule 27.11.2013
comment
Было бы чудесно, если бы это оказалось правдой. К сожалению, это не так, и тут наступает новый эпизод плохих описаний searchPattern в MSDN :) Мне стало любопытно, я провел несколько тестов и вот мои выводы... - person varocarbas; 27.11.2013
comment
@varocarbas действительно... интересно, где использовать ?.OP может использовать *a?.sbs..Хотя для этого потребуется, чтобы a было где-то в имени файла - person Anirudha; 27.11.2013
comment
nodeDirInfo.GetFiles("5?.txt"); возвращает любой файл только с .txt (не .txt какой бы то ни было), содержащий два символа в имени, один из которых равен 5. nodeDirInfo.GetFiles("?.txt"); Возвращает любой файл .txt только с одним символом в имени (не включая .txt какой бы то ни было). Вы можете получить только *.txt, используя подход ????.txt, если знаете максимальную длину имен файлов, которые вы ищете (??.txt перенастраивает все файлы с 1 или 2 символами в имени; ???.txt все те, у которых 1,2 и 3 и т. д.). - person varocarbas; 27.11.2013
comment
это был ответ, который, как я надеялся, сработает. Но '?.sbs' ничего не вернул, а '*?.sbs' вернул все файлы с 'sbs' в расширении. Единственное, что объединяет эти имена файлов, — это расширение. Я полагаю, что это будет иметь место со многими такими поисками. Я согласен с варокарбасом, документы не ясны. - person topofsteel; 28.11.2013