Как сравнить, возможно, альтернативные имена файлов в Windows? - PullRequest
2 голосов
/ 25 апреля 2019

К сожалению, имена каталогов / файлов в Windows не чувствительны к регистру.

Когда я сравниваю текст (ввод от пользователя) с именем каталога (из CFileFind), как я могу проверить, являются ли онизначит один и тот же каталог или нет?Например, C:\PIPPO\ и C:\Pippo\ - это один и тот же каталог, в то время как C:\Pippò\ - это не одно и то же (последний имеет акцент).

Я пытаюсь:

if(CompareString(LOCALE_INVARIANT,NORM_IGNORECASE,q,-1,data_from_CfileFind->txt.GetBuffer(),-1)==CSTR_EQUAL)

(q является [частью] пользовательского ввода)

Это «вид работ», так как он распознает как один и тот же каталог варианты регистров латинского, греческого и кириллического алфавитов, но это сбивает с толку "weiß" и "weiss" (и это две разные директории на моем диске), так что это ненадежно.

[неудачный тест основан на Сравнение и сортировка имен файлов Unicode : я прочиталэто, но не нашел подходящего решения - ссылки, кажется, не работают)

(я также прочитал Windows Invariant Culture Puzzle но, боюсь, я не совсем понял о "культурах"").

Есть какие-нибудь предложения?

Может быть, мне стоит позвонить CompareString() с другими параметрами?Или есть лучший, более простой подход?

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

Под «Windows» я имею в виду 2000 (или, по крайней мере, XP) и более поздние версии.

EDIT (извините, вопрос не был задан в первый раз)

1) Не гарантируется, что введенный пользователем путь ссылается на реально существующий каталог (в этом случае, конечно, они не один и тот же каталог).

2) Я знаю, что файлы и каталоги могут называться очень разными именами из-за ссылок (жестких или программных), subst s, доступа к сети с другим именем или IP на один и тот же компьютер и т. Д., Но ...Я не прошу выявлять все эти случаи.Все, что я хотел бы проверить, это то, что имя, написанное пользователем, является изменением регистра другого существующего варианта (и, например, Windows скажет мне, что файл уже существует, если я попытаюсь создать его с тем же именем).но другой случай).

2-е РЕДАКТИРОВАНИЕ

Это делает работу (по крайней мере, в тех случаях, которые я пытался):

if(CompareStringOrdinal(q,-1,data_from_CfileFind->txt.GetBuffer(),-1,1)==CSTR_EQUAL)

Но CompareStringOrdinal() недоступно в старых версиях Windows.Есть ли эквивалент?

Ответы [ 3 ]

2 голосов
/ 25 апреля 2019

Лучший способ (насколько мне известно) проверить, относятся ли два пути файловой системы к одному и тому же элементу, без , прибегая к сравнению строк, - это либо:

  1. откройте HANDLE s для двух путей, используя CreateFile(), затем получите уникальные идентификаторы файловой системы из HANDLE s и сравните их на равенство.В FAT и NTFS используйте комбинацию dwVolumeSerialNumber и nFileIndex(Low|High) из GetFileInformationByHandle().В ReFS вместо этого используйте комбинацию VolumeSerialNumber и FileId из GetFileInformationByHandleEx(FileIdInfo).Вы можете использовать GetVolumeInformation(), чтобы определить, какая файловая система используется каждым путем.

    Этот подход описан в BY_HANDLE_FILE_INFORMATION и FILE_ID_INFO документации, соответственно:

    Идентификатор (младшая и старшая части) и серийный номер тома однозначно определяют файл на одном компьютере.Чтобы определить, представляют ли два открытых маркера один и тот же файл, объедините идентификатор и серийный номер тома для каждого файла и сравните их.

    128-битный идентификатор файладля файла.Идентификатор файла и серийный номер тома однозначно определяют файл на одном компьютере.Чтобы определить, представляют ли два открытых дескриптора один и тот же файл, объедините идентификатор и серийный номер тома для каждого файла и сравните их.

  2. , использующий подход, независимый от файловой системы SHGetDesktopFolder(), чтобы получить интерфейс IShellFolder для корневого рабочего стола пространства имен Shell, затем разрешите оба пути к абсолютным PIDL с помощью метода IShellFolder::ParseDisplayName() рабочего стола(или используйте отдельную функцию SHParseDisplayName()), а затем сравните PIDL с помощью метода IShellFolder::CompareIDs() рабочего стола.

1 голос
/ 25 апреля 2019

Начните с вызова GetFullPathName на каждом пути, затем выполните GetLongPathName и, наконец, выполните сравнение результатов без учета регистра.

GetFullPathName дастполный путь к каждому файлу.GetLongPathName затем получает реальное имя каждого компонента этого пути, поэтому, если кто-то использовал короткое имя в стиле Windows 95/98 для файла / каталога, это не будет путать вещи.

0 голосов
/ 25 апреля 2019

Вот как это работает:

1) В начале программы вызовите setlocale(LC_CTYPE, "");

2) Затем сравните строки с if(!data_from_CfileFind->txt.CompareNoCase(q)) (который вызывает _wcsicmp, который вызывает _wcsicmp_l)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...