6
votes

Comment ouvrir un fichier avec WCHAR_T * contenant de la chaîne non ASCII à Linux?

Environnement: GCC / G ++ Linux

J'ai un fichier non-ASCII dans le système de fichiers et je vais l'ouvrir.

Maintenant, j'ai un wchar_t *, mais je ne sais pas comment l'ouvrir. (Ma Fopen de confiance ne ouvre que Char * Fichier)

aide s'il vous plaît. Merci beaucoup.


3 commentaires

Le nom de fichier n'est-il pas ASCII, ni le contenu non-ASCII, ou les deux?


Ouais, tous les deux. Il existe Wfstream pour lire / écrire Wcharner dans un fichier, mais Wfstream ouvre également uniquement le fichier Char *.


Convertissez WCHAR en UTF8 Char et essayez fopen () à ce sujet?


6 Réponses :


0
votes

Consultez ce document

http://www.firstobject.com/wchar_t- string-on-linux-osx-windows.htm

Je pense que Linux suit la norme POSIX, qui traite tous les noms de fichiers comme UTF-8.


0 commentaires

0
votes

Je suppose que c'est le nom du fichier contenant des caractères non-ASCII, pas le fichier lui-même, lorsque vous dites "fichier non ASCII dans le système de fichiers". Peu importe ce que le fichier contient.

Vous pouvez le faire avec une fopen normale, mais vous devrez faire correspondre l'encodage des utilisations du système de fichiers.

Cela dépend de quelle version de Linux et de quel système de fichiers utilisez-vous et comment vous l'avez mis en place, mais probablement, si vous êtes chanceux, le système de fichiers utilise UTF-8. Donc, prenez votre wchar_t (qui est probablement une chaîne codée UTF-16?), Convertissez-la en une chaîne de caractères encodée dans UTF-8 et transmettez-la à Fopen.


0 commentaires

1
votes

Convertissez la chaîne WCHAR en chaîne de caractères UTF8, puis utilisez fopen.

typedef unsigned int   uint;
typedef unsigned short word;
typedef unsigned char  byte;

int UTF16to8( wchar_t* w, char* s ) {
  uint  c;
  word* p = (word*)w;
  byte* q = (byte*)s; byte* q0 = q;
  while( 1 ) {
    c = *p++;
    if( c==0 ) break;
    if( c<0x080 ) *q++ = c; else 
      if( c<0x800 ) *q++ = 0xC0+(c>>6), *q++ = 0x80+(c&63); else 
        *q++ = 0xE0+(c>>12), *q++ = 0x80+((c>>6)&63), *q++ = 0x80+(c&63);
  }
  *q = 0;
  return q-q0;
}

int UTF8to16( char* s, wchar_t* w ) {
  uint  cache,wait,c;
  byte* p = (byte*)s;
  word* q = (word*)w; word* q0 = q;
  while(1) {
    c = *p++;
    if( c==0 ) break;
    if( c<0x80 ) cache=c,wait=0; else
      if( (c>=0xC0) && (c<=0xE0) ) cache=c&31,wait=1; else 
        if( (c>=0xE0) ) cache=c&15,wait=2; else
          if( wait ) (cache<<=6)+=c&63,wait--;
    if( wait==0 ) *q++=cache;
  }
  *q = 0;
  return q-q0;
}


3 commentaires

Ne vous inquiétez pas avec Fopen, utilisez simplement votre constructeur de flux normal ou votre membre.


Merci et j'ai résolu mon problème. Le seul problème est que, dans Linux Wchar_t, est égal à uint32. J'ai fait quelques modifications et cela a fonctionné.


Les fonctions de cette réponse sont horriblement non conformes et insécuritées. Recherchez les définitions correctes de l'UTF-8 et de l'UTF-16 si vous souhaitez les utiliser. (Et note que UTF-16 est sans importance que la question de OP puisque wchar_t n'est pas utf-16, sauf sur Windows, et même là, il est plutôt cassé ...)



4
votes

Linux n'est pas UTF-8, mais c'est votre seul choix pour les noms de fichiers de toute façon

(les fichiers peuvent avoir tout ce que vous voulez à l'intérieur eux.)


En ce qui concerne les noms de fichiers, Linux n'a pas vraiment de codage de chaîne pour s'inquiéter. Les noms de fichiers sont des chaînes d'octets qui doivent être résiliées de manière nulle.

Cela ne signifie pas précisément que Linux est UTF-8, mais cela signifie qu'il n'est pas compatible avec de grands caractères car ils pourraient avoir un zéro dans un octet qui n'est pas l'octet de fin.

Mais UTF-8 préserve le modèle NO-NULLS-SAUF-THE-END, je dois donc croire que l'approche pratique est "Convertir en UTF-8" pour les noms de fichiers.

Le contenu des fichiers est une question de normes au-dessus du niveau du noyau Linux, alors il n'y a donc rien de Linux-y que vous pouvez ou de vouloir faire. Le contenu des fichiers sera uniquement la préoccupation des programmes qui les lisent et les écrit. Linux ne fait que stocker et renvoyer le flux d'octets, et il peut avoir toutes les nuls intégrées que vous voulez.


1 commentaires

Cela ne devrait pas être frustrant. C'est en fait le plus simple possible. Il suffit d'utiliser UTF-8 partout et vous n'avez rien à craindre.



15
votes

Il y a deux réponses possibles:

Si vous souhaitez vous assurer que tous les noms de fichiers UNICODE sont représentables, vous pouvez coder en difficulté l'hypothèse que le système de fichiers utilise des noms de fichiers UTF-8. C'est l'approche "moderne" de bureau Linux Desktop-App. Il suffit de convertir vos chaînes de wchar_t (utf-32) sur UTF-8 avec les fonctions de la bibliothèque ( iconv fonctionnerait bien) ou votre propre implémentation (mais recherchez les spécifications afin que vous ne puissiez pas 't vous tromper horriblement comme Shelwien l'a fait), puis utilisez fopen .

Si vous souhaitez faire des choses plus de manière axée sur les normes, vous devez utiliser wcsrtombbs pour convertir la chaîne wchar_t à un char String dans l'encodage de la locale (ce qui espérons-le, est UTF-8 de toute façon sur tout système moderne) et utilisez fopen . Notez que cela nécessite que vous définissez précédemment la locale avec setlocale (lc_ctype, "") ou setLocale (lc_all, "") . .

et enfin, pas exactement une réponse, mais une recommandation:

stocker des noms de fichiers comme wchar_t cordes est probablement une erreur horrible. Vous devriez plutôt stocker les noms de fichiers comme des chaînes d'octets abstraits et ne convertissez que celles en wchar_t juste à temps pour les afficher dans l'interface utilisateur (si elle est même nécessaire pour cela; de nombreuses outils à outils d'interface utilisateur utilisent des cordes unies d'octets eux-mêmes et faire l'interprétation comme des personnages pour vous). De cette façon, vous éliminez beaucoup de cas d'angle méchants possibles et vous ne rencontrez jamais une situation dans laquelle certains fichiers sont inaccessibles en raison de leurs noms.


1 commentaires

Merci. C'est la façon dont je cherche.



0
votes
// locals
string file_to_read;           // any file
wstring file;                  // read ascii or non-ascii file here 
FILE *stream;
int read = 0;    
wchar_t buffer= '0';

if( fopen_s( &stream, file_to_read.c_str(), "r+b" ) == 0 )   // in binary mode
  {      
      while( !feof( stream ))
      { 
     // if ascii file second arg must be sizeof(char). if non ascii file sizeof( wchar_t)
        read = fread( & buffer, sizeof( char ), 1, stream );  
        file.append(1, buffer);
      }
  }

file.pop_back(); // since this code reads the last character twice.Throw the last one
fclose(stream);

// and the file is in wstring format.You can use it in any C++ wstring operation
// this code is fast enough i think, at least in my practice
// for windows because of fopen_s

0 commentaires