В какой кодировке хранятся имена файлов в NTFS? - PullRequest
39 голосов
/ 12 января 2010

Я только начинаю программирование для обработки имен файлов с неанглийскими именами в системе WinXP. Я порекомендовал кое-что почитать по юникоду и думаю, что понял основную идею, но некоторые части мне все еще не очень понятны.

В частности, в какой кодировке (UTF-8, UTF-16LE / BE) файл имен (не содержимое, а фактическое имя файла) хранится в NTFS? Можно ли открыть какой-либо файл, используя fopen (), который принимает символ char *, или у меня нет другого выбора, кроме как использовать wfopen (), который использует wchar_t * и предположительно принимает строку UTF-16?

Я попытался вручную ввести строку в кодировке UTF-8 в fopen (), например.

unsigned char filename[] = {0xEA, 0xB0, 0x80, 0x2E, 0x74, 0x78, 0x74, 0x0}; // 가.txt

FILE* f = fopen((char*)filename, "wb+");

но это получилось как 'ê ° € .txt'.

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

Может кто-нибудь пролить свет на это?

Ответы [ 3 ]

36 голосов
/ 12 января 2010

NTFS хранит имена файлов в UTF16, однако fopen использует ANSI (не utf8).

Чтобы использовать имя файла в кодировке UTF16, вам необходимо использовать Unicode-версии вызовов открытия файлов. Сделайте это, определив UNICODE и _UNICODE в вашем проекте. Затем используйте вызов CreateFile или вызов wfopen.

14 голосов
/ 12 января 2010

fopen () - в MSVC для Windows (по умолчанию) не принимает кодированный в utf-8 символ *.

К сожалению, utf-8 был изобретен сравнительно недавно по великой схеме вещей. Windows API делятся на версии Unicode и Ansi. каждый Windows API, который принимает или обрабатывает строки, фактически доступен с суффиксом W или A - W для «широкого» символа / Unicode и A для Ansi. Макро-магия скрывает все это от разработчика, поэтому вы просто вызываете CreateFile с типом char * или wchar_t * в зависимости от конфигурации вашей сборки, не зная разницы.

Кодировка 'Ansi' на самом деле не является конкретной кодировкой: - Но это означает, что кодировка, используемая для строк "char", специфична для настройки языка ПК.

Теперь, поскольку функции времени выполнения c - такие как fopen - должны работать по умолчанию без ведома разработчика - в системах Windows они ожидают получить свои строки в локальной кодировке Windows. msdn указывает, что API-интерфейс Microsoft c-runtime может изменить локаль текущего потока, но, в частности, говорит, что он потерпит неудачу для любых локалей, которым требуется более 2 байтов на символ - например, utf-8.

Итак, в Windows нет ярлыка. Вам нужно , чтобы использовать wfopen или собственный API CreateFileW (или создать свой проект с использованием настроек сборки Unicode и просто вызвать Createfile) со строками wchar_t *.

5 голосов
/ 07 ноября 2014

Как ответили другие, лучший способ обработки строк в кодировке UTF-8 - это преобразовать их в UTF-16 и использовать собственные API-интерфейсы Unicode, такие как _wfopen или CreateFileW.

Однако этот подход не поможет при обращении к библиотекам, которые используют fopen() безоговорочно, потому что они не поддерживают Unicode или потому что они написаны на переносимом C. В этом случае все еще можно использовать устаревшее " короткие пути »для преобразования строки в кодировке UTF-8 в форму ASCII, используемую с fopen, но для этого требуется некоторая работа:

  1. Преобразование представления UTF-8 в UTF-16 с использованием MultiByteToWideChar.

  2. Используйте GetShortPathNameW, чтобы получить «короткий путь», который предназначен только для ASCII. GetShortPathNameW вернет его в виде широкой строки со всем содержимым ASCII, которое вам нужно будет просто преобразовать в узкую строку путем приведения копии без потерь при каждом wchar_t char.

  3. Передайте короткий путь к fopen() или к коду, который в конечном итоге будет использовать fopen(). Помните, что сообщения об ошибках, напечатанные этим кодом, если таковые имеются, будут ссылаться на неприглядный «короткий путь» (например, KINTO~1 вместо kinto-un-筋斗雲).

Хотя это не совсем рекомендуемая долгосрочная стратегия, поскольку короткие пути Windows являются устаревшей функцией, которую можно отключить для каждого тома, вероятно, это единственный способ передать имена файлов в код, который использует fopen() и другие вызовы API, связанные с файлами (stat, access, версии ANSI CreateFile и аналогичные).

...