web-dev-qa-db-fra.com

Sous quel encodage les noms de fichiers dans NTFS sont-ils stockés?

Je viens de commencer une programmation pour gérer les noms de fichiers avec des noms non anglais sur un système WinXP. J'ai fait une lecture recommandée sur unicode et je pense avoir l'idée de base, mais certaines parties ne sont toujours pas très claires pour moi.

Plus précisément, quel encodage (UTF-8, UTF-16LE/BE) le fichier noms (pas le contenu, mais le nom réel du fichier) est-il stocké dans NTFS? Est-il possible d'ouvrir n'importe quel fichier en utilisant fopen (), qui prend un char *, ou n'ai-je pas d'autre choix que d'utiliser wfopen (), qui utilise un wchar_t *, et prend vraisemblablement une chaîne UTF-16?

J'ai essayé d'introduire manuellement une chaîne encodée UTF-8 dans fopen (), par exemple.

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

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

mais cela est sorti comme "ê ° € .txt".

J'avais l'impression (ce qui peut être faux) qu'une chaîne encodée en UTF8 suffirait pour ouvrir n'importe quel nom de fichier sous Windows, car il semble que je me souviens vaguement d'une application Windows passant (char *), pas (wchar_t *), et ayant pas de problème.

Quelqu'un peut-il faire la lumière là-dessus?

41
vroooom

NTFS stocke les noms de fichiers dans UTF-16, cependant fopen utilise ANSI (pas UTF-8).

Pour utiliser un nom de fichier encodé en UTF16, vous devrez utiliser les versions Unicode des appels d'ouverture de fichier. Pour ce faire, définissez UNICODE et _UNICODE dans votre projet. Utilisez ensuite l'appel CreateFile ou l'appel wfopen.

38
villintehaspam

fopen () - dans MSVC sur Windows ne prend pas (par défaut) un caractère encodé en utf-8 *.

Malheureusement, l'utf-8 a été inventé assez récemment dans le grand schéma des choses. Les API Windows sont divisées en versions Unicode et Ansi. tous Windows api qui prend ou traite des chaînes est en fait disponible avec un suffixe W ou A - W pour le caractère "Wide"/Unicode et A pour Ansi. La magie des macros cache tout cela loin du développeur, vous appelez donc simplement CreateFile avec un char * ou un wchar_t * en fonction de la configuration de votre build sans connaître la différence.

L'encodage 'Ansi' n'est en fait pas un encodage spécifique: - mais signifie que l'encodage utilisé pour les chaînes "char" est spécifique au paramètre local du PC.

Maintenant, parce que les fonctions d'exécution c - comme fopen - doivent fonctionner par défaut à l'insu des développeurs - sur les systèmes Windows, elles s'attendent à recevoir leurs chaînes dans l'encodage local Windows. msdn indique que l'api setlocal de Microsoft c-runtime peut changer les paramètres régionaux du thread actuel - mais indique spécifiquement qu'il échouera pour tous les paramètres régionaux qui nécessitent plus de 2 octets par caractère - comme utf-8.

Donc, sous Windows, il n'y a pas de raccourci. Vous avez besoin pour utiliser wfopen, ou l'API native CreateFileW (ou créez votre projet en utilisant les paramètres de construction Unicode et appelez simplement Createfile) avec des chaînes wchar_t *.

14
Chris Becke

Comme d'autres l'ont répondu, la meilleure façon de gérer les chaînes encodées en UTF-8 est de les convertir en UTF-16 et d'utiliser des API Unicode natives telles que _wfopen Ou CreateFileW.

Cependant, cette approche n'aidera pas lors de l'appel à des bibliothèques qui utilisent fopen() sans condition car elles ne prennent pas en charge Unicode ou parce qu'elles sont écrites en C. portable. Dans ce cas, il est toujours possible d'utiliser l'héritage "chemins courts" pour convertir une chaîne encodée en UTF-8 en une forme ASCII utilisable avec fopen, mais cela nécessite un peu de travail:

  1. Convertissez la représentation UTF-8 en UTF-16 en utilisant MultiByteToWideChar .

  2. Utilisez GetShortPathNameW pour obtenir un "chemin court" qui est uniquement ASCII. GetShortPathNameW la renverra sous la forme d'une chaîne large avec un contenu entièrement ASCII, dont vous aurez besoin pour la convertir trivialement en une chaîne étroite par une copie sans perte qui convertit chaque wchar_tchar.

  3. Passez le chemin court à fopen() ou au code qui utilisera éventuellement fopen(). Sachez que les messages d'erreur imprimés par ce code, le cas échéant, feront référence au "chemin court" disgracieux (par exemple KINTO~1 Au lieu de kinto-un-筋斗雲).

Bien que ce ne soit pas exactement une stratégie à long terme recommandée, comme les chemins d'accès courts de Windows sont une fonctionnalité héritée qui peut être désactivée par volume, c'est probablement le seul moyen de passer des noms de fichiers au code qui utilise fopen() et d'autres appels d'API liés aux fichiers (stat, access, versions ANSI de CreateFile et similaires).

5
user4815162342