Как бороться с Windows ReadDirectoryChangesW () и смешанным выводом длинного / короткого имени файла? - PullRequest
9 голосов
/ 14 ноября 2010

Я разрабатываю фрагмент кода на C, который использует ReadDirectoryChangesW () для мониторинга изменений в каталоге в Windows. Я прочитал соответствующие записи MSDN для ReadDirectoryChangesW () и структуры FILE_NOTIFY_INFORMATION, а также несколько других частей документации. На данный момент мне удалось контролировать несколько каталогов без каких-либо явных проблем в самом мониторинге. Проблема состоит в том, что имена файлов, помещенные в структуру FILE_NOTIFY_INFORMATION этой функцией, не являются каноническими.

В соответствии с MSDN они могут быть в длинной или короткой форме. Я нашел несколько сообщений, которые предлагают кэширование как коротких, так и длинных путей для обработки этого случая. К сожалению, согласно моему собственному тестированию в системе Windows 7 этого недостаточно для устранения проблемы, потому что для каждого имени файла не существует только двух альтернатив. Проблема в том, что в имени пути КАЖДЫЙ КОМПОНЕНТ может быть в длинной или короткой форме. Следующие пути могут относиться к одному и тому же файлу:

C: \ PROGRA ~ 1 \ MyProg ~ 1 \ MYDATA ~ 1.TXT

C: \ PROGRA ~ 1 \ MyProg ~ 1 \ MyDataFile.txt

C: \ PROGRA ~ 1 \ MyProgram \ MYDATA ~ 1.TXT

C: \ PROGRA ~ 1 \ MyProgram \ MyDataFile.txt

c: \ Program Files \ MYPROG ~ 1 \ MYDATA ~ 1.TXT

...

и, насколько я могу судить по моему тестированию с использованием cmd.exe, все они вполне приемлемы. По сути, число допустимых имен путей для каждого файла растет экспоненциально с количеством компонентов в его имени пути.

К сожалению, ReadDirectoryChangesW (), похоже, заполняет свой выходной буфер именами файлов, предоставленными системному вызову, который вызывает каждую операцию. Например, если вы используете команды cmd.exe для создания, переименования, удаления файла e.t.c. В файлах FILE_NOTIFY_INFORMATION будет содержать имена файлов, указанные в командной строке.

Теперь в большинстве случаев я мог использовать GetLongPathName () и друзей, чтобы получить уникальный путь для моего использования. К сожалению, этого нельзя сделать при удалении файлов - к тому времени, как я получу уведомление, файл уже исчезнет, ​​и функции Get * PathName () не будут работать.

В настоящий момент я думаю об использовании более обширного кэширования для определения того, какие альтернативные имена путей используются приложениями для каждого файла, что будет обрабатывать любой случай, кроме случая, когда кто-то решает удалить файл на ровном месте, невидимый смешанный путь. И я думаю о творческом извлечении данных из событий модификации родительского каталога и возвращаюсь к проверке действительного каталога для этого случая.

Есть предложения, как сделать это проще?

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

PS2: Пожалуйста, имейте в виду, что я пишу в основном для Unix, так что будьте осторожны ...

1 Ответ

2 голосов
/ 15 ноября 2010

Вам не нужно кэшировать каждую комбинацию.Это будет делать, если вы кешируете каждый подпуть, чтобы иметь возможность преобразовать его в длинную форму.например, сохранить это:

  • C:\PROGRA~1 => c:\Program Files
  • c:\Program Files\MYPROG~1 => c:\Program Files\MyProgram
  • c:\Program Files\MyProgram\MYDATA~1.TXT => c:\Program Files\MyProgram\MyDataFile.txt
  • c:\Program Files\MyProgram\MYDATA~2.TXT => c:\Program Files\MyProgram\MyDataFile2.txt

Теперь, если вы получили уведомление о c:\PROGRA~1\MYPROG~1\MYDATA~1.TXT, разделите его на каждый \ и ищите каждую часть на предмет ее длинной формы.

Не забывайте, что MyDataFile.txt и MYDATAFILE.TXT также указывают на один и тот же файл.Так что сравнивайте без учета регистра или преобразуйте все в верхний регистр.

И если c:\PROGRA~1\MYPROG~1\MYDATA~1.TXT удалено, вы все равно можете использовать GetLongPathName() на c:\PROGRA~1\MYPROG~1.

...