Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Problème wifstream et fichiers unicodes

6 réponses
Avatar
Davidbrcz
Bonjour =E0 tous.
Je tente de d=E9couvrir lla gestion des fichiers en unicode mais le code
ne renvoit rien pour une raison qui m'=E9chappe.
Le voici, tout ce qu'il y a de plus simple:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

int main(int argc, char const *argv[])
{
std::wifstream flx("liste.txt", std::ios::in);
if(flx){
std::wcout<<L"Ok"<<std::endl;
std::wstring s;

std::wstringstream buffer;
buffer << flx.rdbuf();
std::wcout << L"Taille du buffer : " << buffer.str().size
() << std::endl;
}
else{
std::wcout<<L"erreur"<<std::endl;
}
return 0;
}

Que je tente de lire le fichier en entier, ou que je tente une lecture
ligne par ligne avec std::getline, s reste vide.

ce qui est =E9trange, c'est qu'une lecture avec ifstream/string/...
marche, aux accents pr=E8s (d'o=F9 la raison de mon passage en unicode).

Merci d'avance.
David C=F4me

6 réponses

Avatar
James Kanze
On May 21, 12:18 pm, Davidbrcz wrote:

Je tente de découvrir lla gestion des fichiers en unicode mais
le code ne renvoit rien pour une raison qui m'échappe. Le
voici, tout ce qu'il y a de plus simple:



#include <iostream>
#include <string>
#include <fstream>
#include <sstream>



int main(int argc, char const *argv[])
{
std::wifstream flx("liste.txt", std::ios::in);
if(flx){
std::wcout<<L"Ok"<<std::endl;
std::wstring s;



std::wstringstream buffer;
buffer << flx.rdbuf();
std::wcout << L"Taille du buffer : " << buffer.str().size
() << std::endl
}
else{
std::wcout<<L"erreur"<<std::endl;
}
return 0;
}



Que je tente de lire le fichier en entier, ou que je tente une
lecture ligne par ligne avec std::getline, s reste vide.



Ça doit dépendre de l'implémentation, ET du locale. Par défaut,
le flux utilise le locale global, et par défaut, le locale
global est "C". Avec g++, par exemple, sous Linux (et je
suppose, les Unix aussi), la lecture en locale "C" s'arrête au
premier caractère avec un encodage supérieur à 127. (On peut
discuter si c'est un bon choix du point de vue de la qualité de
l'implémentation, mais dans la pratique, c'est difficile à
savoir ce que doit faire l'implémentation si elle ne connaît pas
l'encodage du fichier. Et c'est le locale qui lui en informe.)
Avec VC++ sous Windows, on lit tout le fichier (parce que
Windows définit un encodage « officiel » ?).

En général, dès qu'un programme traite du texte, même de la
façon la plus simple, la première instruction dans main doit
être :
std::locale::global( std::locale( "" ) ) ;
Cette instruction initialise le locale global (et donc, celui
qui servira à tout [io]stream ou w[io]stream créé par la suite)
au locale courant de l'environement. Si je fais ceci, ton code
marche aussi avec g++ sous Linux (à condition de ne pas avoir
des incohérences dans mes variables de locale -- LANG=fr mais
LC_CTYPE=en_US, par exemple, ne marche pas).

ce qui est étrange, c'est qu'une lecture avec
ifstream/string/... marche, aux accents près (d'où la raison
de mon passage en unicode).



Qu'est-ce que ça veut dire, « aux accents près ». Les
[io]fstream en locale "C" doivent être transparent. (Selon la
norme, « codecvt<char,char,mbstate_t> implements a degenerate
conversion; it does not convert at all.) Tu dois donc retrouver
le contenu complet de ton fichier dans la chaîne s. (En fait,
j'utilise bien ifstream et ofstream, imbué du locale "C" et
ouvert en mode binaire, pour l'écriture et la lecture de
l'UTF-8. Sous Linux, Solaris et Windows, avec g++, Sun CC et
VC++, sans problème.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Sylvain Togni
Davidbrcz a écrit :

Je tente de découvrir lla gestion des fichiers en unicode mais le code
ne renvoit rien pour une raison qui m'échappe.



Attention, wchar_t ne veut pas forcement dire Unicode. Notamment
sous Windows wchar_t fait seulement 16 bits, ce qui est insuffisant
pour contenir tous les caractères Unicode. La norme définie juste
wchar_t comme étant au moins aussi grand que char, sans spécifier
quoi que se soit d'autre.

Que je tente de lire le fichier en entier, ou que je tente une lecture
ligne par ligne avec std::getline, s reste vide.



Surement une inadéquation entre l'encodage du fichier et le codecvt
(classe utilisée par les stream C++ pour décoder les fichiers
textes).

A chaque encodage (ISO-8859-1, Windows-1252, UTF-8, UTF-16LE, ...)
doit correspond un codecvt différent. La première chose à faire est
donc de déterminer quel est l'encodage du fichier à lire.

ce qui est étrange, c'est qu'une lecture avec ifstream/string/...
marche, aux accents près (d'où la raison de mon passage en unicode).



Ce qui semble orienter vers un encodage 8-bits, surement un de ces
trois là : ISO-8859-1, Windows-1252, UTF-8.

Le codecvt peut être changé de deux façons. Exemple pour l'UTF-8 :

- En changeant la locale du flux (en supposant qu'une telle locale
existe sur la machine)

flx.imbue(std::locale("fr_FR.UTF-8"));

- En changeant juste le codecvt (en supposant qu'un tel codecvt
existe)

flx.imbue(std::locale(std::locale(),
new utf8_codecvt_facet<wchar_t>));

Bref, rien de parfaitement portable, hélas.

Utiliser wfstream plutôt que fstream ne change pas forcement grand
chose en terme d'encodage, juste la possibilité de gérer des charset
de plus de 256 caractères.

--
Sylvain
Avatar
James Kanze
On May 22, 11:56 am, Sylvain Togni <"sylvain.togni at
visionobjects.com"> wrote:
Davidbrcz a écrit :



> Je tente de découvrir lla gestion des fichiers en unicode
> mais le code ne renvoit rien pour une raison qui m'échappe.

Attention, wchar_t ne veut pas forcement dire Unicode.



C'est vrai. Et char ne veut pas forcement dire quelque chose qui
dérive d'ASCII.

Dans la pratique, le problème n'existe que sur des systèmes
« historiques », genre Solaris (pour Unicode sur wchar_t) et les
mainframes (EBCDIC plutôt qu'ASCII). Dans les cas de wchar_t,
typiquement (ou, disons plutôt, au moins dans le cas de
Solaris), tu peux aussi utiliser Unicode dans les wchar_t ; il
n'y a pas vraiment des appels systèmes où il fait une
différence. (Et en fait, la bibliothèque de C respectera un
locale Unicode.)

Notamment sous Windows wchar_t fait seulement 16 bits, ce qui
est insuffisant pour contenir tous les caractères Unicode.



Windows wchar_t est UTF-16. Un format d'encodage Unicode.

La norme définie juste wchar_t comme étant au moins aussi
grand que char, sans spécifier quoi que se soit d'autre.



En ce qui concerne la norme C++, certes. La norme C++ ne dit
rien en ce qui concerne les encodages (encore -- la prochaine
version imposera un support minimum pour UTF-8, UTF-16 et
UTF-32). Dans la pratique, si tu n'es concerné que par des
systèmes Unix et Windows, wchar_t est Unicode, à condition
(parfois) d'utiliser le bon locale.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Davidbrcz
Désolé de ne pas avoir répondu plus tôt mais ma connexion fait des
siennes.

Le fichier est en UTF-16. Je n'ai pas testé mon code sous windows mais
je pense qu'il devrait marcher.

Message 1 de James:
=> pas de problème particulier pour mes variables, tout est logique.
=> le fixage de la locale ne change rien.
=> aux accent près veut dire qu'a la place des caractères accentués ,
j'ai des caractères tout laids genre ?

Message de Sylvain:
=> j'essaye d'adapter le code à l'utf 16 mais rien ne marche (erreur à
l'exécution ou à la compilation respectivement).
Je vais continuer à chercher
Avatar
James Kanze
On May 23, 5:42 pm, Davidbrcz wrote:

Le fichier est en UTF-16. Je n'ai pas testé mon code sous windows mais
je pense qu'il devrait marcher.



Message 1 de James:
=> pas de problème particulier pour mes variables, tout est logique.
=> le fixage de la locale ne change rien.
=> aux accent près veut dire qu'a la place des caractères accentu és,
j'ai des caractères tout laids genre ?



C'est un symptome fréquent quand le locale ne correspond pas à
l'encodage. Il faudrait voir s'il y a un locale UTF16 installé
sur la machine. C'est assez rare sous les Unix. Sous les Linux
auxquels j'ai accès, il n'y a même pas indication de
l'encodage ; je crois que le défaut, c'est UTF-8, dans ces
cas-là, mais je ne suis pas sûr. Il te faut quelque chose du
genre "fr_FR.utf16le" (Voir dans /usr/share/locale ou
/usr/lib/locale.)

À tout hazard, essaie de convertir ton fichier en UTF-8, au
moyen d'iconv, pour voir si ça marche mieux. (Si c'est le cas,
tu sais au moins de quoi il s'agit.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Jean-Marc Bourguet
James Kanze writes:

On May 23, 5:42 pm, Davidbrcz wrote:

Le fichier est en UTF-16. Je n'ai pas testé mon code sous windows mais
je pense qu'il devrait marcher.



Message 1 de James:
=> pas de problème particulier pour mes variables, tout est logique.
=> le fixage de la locale ne change rien.
=> aux accent près veut dire qu'a la place des caractères accentués,
j'ai des caractères tout laids genre ?



C'est un symptome fréquent quand le locale ne correspond pas à
l'encodage. Il faudrait voir s'il y a un locale UTF16 installé
sur la machine.



Est-ce que c'est conforme?

Ce n'est à coup sûr pas conforme comme "multibyte encoding" interne en C --
5.2.1.2/1 impose que ne soit pas présent -- mais comme format sur disque
je n'en sais rien. (Et j'ai la flemme de vérifier si C++ on a une
contrainte explicite similaire, ou qu'on en hérite, ou qu'on en hérite pas,
j'ai mal à la tête chaque fois que j'essaie de faire un résumé de ce qui
est conforme en la matière).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org