Quel encodage les noms de fichiers en NTFS sont-ils stockés?
Je commence juste à programmer pour gérer les noms de fichiers avec des noms Non anglais sur un Système WinXP. J'ai fait quelques lectures recommandées sur unicode et je pense que j'ai 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) les noms de fichiers (pas le contenu, mais le nom réel du fichier) sont-ils stockés 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 de utilisez wfopen (), qui utilise un wchar_t*, et prend probablement une chaîne UTF-16?
J'ai essayé d'alimenter manuellement une chaîne encodée en UTF-8 à 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 à ouvrir n'importe quel nom de fichier sous Windows, car je me souviens vaguement de certaines applications Windows qui passaient (char*), pas (wchar_t*), et n'ayant aucun problème.
Quelqu'un peut-il en perdre la lumière sur cette?
3 réponses
NTFS stocke les noms de fichiers en UTF16, mais fopen utilise ANSI (pas utf8).
Pour utiliser un nom de fichier codé en UTF16, vous devez utiliser les versions Unicode des appels d'ouverture de fichier. Pour ce faire, définissez UNICODE et _UNICODE dans votre projet. Ensuite, utilisez L'appel CreateFile ou l'appel wfopen.
Fopen ()-dans MSVC sous windows ne prend pas (par défaut) un caractère encodé utf-8*.
Malheureusement 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. chaque api windows qui prend ou traite des chaînes est réellement disponible avec un W ou un suffixe-W pour le caractère" large " /Unicode et un pour Ansi. Macro magic cache tout cela loin du développeur, donc vous appelez simplement CreateFile avec un char* ou un wchar_t * en fonction de votre configuration de construction 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 aux paramètres régionaux du PC.
Maintenant, parce que les fonctions C-runtime - comme fopen-doivent fonctionner par défaut sans connaissance des développeurs-sur les systèmes windows, elles s'attendent à recevoir leurs chaînes dans l'encodage local de windows. msdn indique l'api Microsoft C-runtime setlocal peut changer les paramètres régionaux du thread actuel - mais dit spécifiquement qu'il échouera pour tous les paramètres régionaux qui ont besoin de plus de 2 Octets par caractère-comme utf-8.
Donc, sous Windows, il n'y a pas de raccourci. Vous avez besoin de 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*.
Comme d'autres ont répondu, la meilleure façon de gérer les chaînes encodées en UTF-8 est de les convertir en Unicode et d'utiliser des API Unicode natives telles que _wfopen
ou CreateFileW
.
Cependant, cette approche n'aidera pas lors de l'appel dans des bibliothèques qui utilisent fopen()
inconditionnellement parce qu'elles ne supportent pas Unicode ou parce qu'elles sont écrites en portable C. Dans ce cas, il est toujours possible d'utiliser les "chemins courts" hérités pour convertir une chaîne encodée en UTF-8 en une forme ASCII utilisable avec fopen
, mais nécessite un travail sur le terrain:
Convertir la représentation UTF-8 en UTF-16 en utilisant
MultiByteToWideChar
.Utilisation
GetShortPathNameW
pour obtenir un "chemin court" qui est uniquement ASCII.GetShortPathNameW
Le retournera comme une chaîne large avec du contenu tout-ASCII, que vous aurez besoin de convertir trivialement en une chaîne étroite par une copie sans perte coulée chaquewchar_t
char
.Passez le chemin court à
fopen()
ou au code qui finira par utiliserfopen()
. Soyez conscient de cette erreur les messages imprimés par ce code, le cas échéant, se référeront au "chemin court" disgracieux (par exempleKINTO~1
au lieu dekinto-un-筋斗雲
).
Bien que ce ne soit pas exactement une stratégie à long terme recommandée, car les chemins courts de Windows sont une fonctionnalité héritée qui peut être désactivée par volume, c'est probablement le seul moyen de transmettre des noms de fichiers au code qui utilise fopen()
et d'autres appels API liés aux fichiers (stat
, access
, les versions ANSI de CreateFile
et similaires).