Comment puis-je lire les chaînes Unicode-16 d'un fichier en utilisant les méthodes POSIX dans Linux?
j'ai un fichier contenant UNICODE-16 chaînes que je voudrais lire dans un programme Linux. Les chaînes ont été écrites raw à partir du format wchar interne de Windows. (Windows utilise-t-il toujours UTF-16? par exemple dans les versions japonaises)
je crois que je peux les lire en utilisant des lectures brutes et la conversion avec wcstombs_l. Cependant, je ne sais pas quel endroit utiliser. L'exécution "locale-a" sur mes machines Ubuntu et Mac OS X à jour donne zéro locales avec utf-16 dans leur nom.
y a-t-il un meilleur moyen?
mise à jour: la bonne réponse et d'autres ci-dessous m'ont aidé à utiliser libiconv. Voici une fonction que j'utilise pour faire la conversion. Je l'ai actuellement dans une classe qui fait les conversions en une seule ligne de code.
// Function for converting wchar_t* to char*. (Really: UTF-16LE --> UTF-8)
// It will allocate the space needed for dest. The caller is
// responsible for freeing the memory.
static int iwcstombs_alloc(char **dest, const wchar_t *src)
{
iconv_t cd;
const char from[] = "UTF-16LE";
const char to[] = "UTF-8";
cd = iconv_open(to, from);
if (cd == (iconv_t)-1)
{
printf("iconv_open("%s", "%s") failed: %sn",
to, from, strerror(errno));
return(-1);
}
// How much space do we need?
// Guess that we need the same amount of space as used by src.
// TODO: There should be a while loop around this whole process
// that detects insufficient memory space and reallocates
// more space.
int len = sizeof(wchar_t) * (wcslen(src) + 1);
//printf("len = %dn", len);
// Allocate space
int destLen = len * sizeof(char);
*dest = (char *)malloc(destLen);
if (*dest == NULL)
{
iconv_close(cd);
return -1;
}
// Convert
size_t inBufBytesLeft = len;
char *inBuf = (char *)src;
size_t outBufBytesLeft = destLen;
char *outBuf = (char *)*dest;
int rc = iconv(cd,
&inBuf,
&inBufBytesLeft,
&outBuf,
&outBufBytesLeft);
if (rc == -1)
{
printf("iconv() failed: %sn", strerror(errno));
iconv_close(cd);
free(*dest);
*dest = NULL;
return -1;
}
iconv_close(cd);
return 0;
} // iwcstombs_alloc()
4 réponses
(Windows utilise-t-il toujours UTF-16? par exemple dans les versions japonaises)
Oui, le WCHAR de NT est toujours UTF-16LE.
(le’ System codepage', qui pour les installations japonaises est en effet cp932/Shift-JIS, existe toujours dans NT pour le bénéfice des nombreuses, nombreuses applications qui ne sont pas Unicode-native, FAT32 paths, et ainsi de suite.)
cependant, wchar_t n'est pas garanti d'être 16 bits et sur Linux il ne sera pas, UTF-32 (UCS-4) est utilisé. Il est donc peu probable que wcstombs_l soit heureux.
la bonne chose serait d'utiliser une bibliothèque comme iconv pour la lire dans n'importe quel format que vous utilisez en interne - probablement wchar_t. Vous pourrait essayer de le pirater vous-même en insérant des octets, mais vous obtiendriez probablement des choses comme les substituts faux.
Runing "paramètres régionaux" sur ma mise à jour de Ubuntu et Mac OS X machines rendements zéro locales avec utf-16 en leur nom.
en effet, Linux ne peut pas utiliser UTF-16 comme encodage local par défaut grâce à tous les \0s.
la manière la plus simple est de convertir le fichier de utf16 à utf8 encodage UNIX natif, puis de le lire,
iconv -f utf16 -t utf8 file_in.txt -o file_out.txt
vous pouvez également utiliser iconv(3) (Voir man 3 iconv) pour convertir la chaîne en utilisant C. La plupart des autres langues ont aussi des fixations à iconv.
que vous pouvez utiliser N'importe quelle locale UTF-8 comme en_US.UTF-8 qui sont habituellement celui par défaut sur la plupart des distributions linux.
Vous pouvez lire en binaire, puis faire votre propre conversion rapide: http://unicode.org/faq/utf_bom.html#utf16-3 Mais il est probablement plus sûr d'utiliser une bibliothèque (comme libiconv) qui gère les invalides séquences correctement.
je recommande fortement d'utiliser un encodage Unicode comme représentation interne de votre programme. Utilisez L'UTF-16 ou L'UTF-8. Si vous utilisez UTF-16 en interne, il est évident qu'aucune traduction n'est nécessaire. Si vous utilisez UTF-8, Vous pouvez utiliser une locale avec .UTF-8
comme en_US.UTF-8
.