Или небольшая заметка про странный глюк (на самом деле фичу) MS и кривофикс к ней.
Словил странный баг при поиске файлов по маске, функцией Directory.GetFiles();
Оказалось, что при задании маски вида *.htm
, в выборке окажутся все файлы с расширением, длина которого больше трех совпадающих символов, т.е. и *.htm
и *.html
и *.htmепрст
, и т.д. Срабатывает это для файлов с расширениями размером три символа и больше.
Т.е. на *.ph
оно найдет только файлы с расширением ph
, а на *.a
— только файлы с расширением a
Этот баг распространяется только на последнее расширение. Если в имени файла есть конструкция типа *.tmp.php
, например admin.tmp.php
, то при задании маски *.php
расширение tmp
будет, слава Ктулху, проигнорировано.
Оказалось, что это не баг, а фича, и об этом прямо написано в MSDN:
Не знаю, как создатели DOS смогли заговнять и испортить самую простую операцию, которая работала у них, как минимум, с 1989 года, но факт. Заговняли.
В общем, я теряюсь в догадках.
Это, конечно же, довольно коряво. Наверное, можно было бы решить с помощью регулярных выражений, но я поступил следующим образом:
1. Создал функцию, которая будет вытаскивать однозначное расширение и из заданной маски, и из поданного на вход файла:
private string GetExtension(string FileName) { FileName = FileName.Replace('*', '_'); FileName = FileName.Replace('?', '-'); FileInfo fi = new FileInfo(FileName); return fi.Extension; }
Замены Replace(...)
тут для того, чтобы класс FileInfo
не выпал в Exeption, если ему подать что-то вида *.html
, т.к. FileInfo
не принимает имен с недопустимыми символами, к которым относятся и маски подстановки. В определении расширений класс FileInfo
такого глюка не имеет, и отличает file.html
от file.htm
. И тоже не признает двойные расширения, учитывая только последнее.
2. В функции, где будем вызывать поиск файлов, вызываем, собственно, функцию поиска:
string[] files = Directory.GetFiles(Path, Mask, SearchOptions);
3. Получаем расширение маски:
string MaskExt = GetExtension(Mask);
4. Далее обрабатываем выходной массив. Например, тут я добавлял его в List<string>
с именем FoundFiles
. Мне надо было искать файлы по маскам, и нужно было, чтоб *.htm
и, например, *.html
различались.
Например, я просто сравнивал расширение от маски файла с расширением от имени файла, и если оно совпадало — добавлял в результирующий список FoundFiles
:
string FileExt = GetExtension(filename); if (FileExt == MaskExt) { FoundFiles.Add(filename); }
Или относительно полностью:
string MaskExt = GetExtension(Mask); //[...] string[] files = Directory.GetFiles(Path, Mask, SearchOptions); foreach (string filename in files) { string FileExt = GetExtension(filename); if (FileExt == MaskExt) { FoundCtr++; FoundFiles.Add(filename); } }
Pingback: C#, поиск файла по маске, более правильное решение. | Персональный блог Толика Панкова