IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Ifstream + Nom de fichier caractères spéciaux


Sujet :

C++

  1. #1
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut Ifstream + Nom de fichier caractères spéciaux
    Bonjour à tous,
    Mon objectif est de pouvoir ouvrir en lecture ou en écriture un fichier contenant des caractères spéciaux dans le nom de fichier, mais c'est la que ca coince.
    J'arrive à lire oU modifier des fichiers contenant des accents ou autre mais dès qu'il y a un caractère special cela ne fonctionne pas.
    Avec la function CreateFileW, j'arrive à les lire (en envoyant un wchar_t) mais je souhaiterais pouvoir utiliser ifstream/ofstream etant donné que c'est un programme qui j'avais fait pour Linux et que je dois le modifier pour le faire fonctionner sous windows et vu que j'ai utiliser des fstreams partout dans mon programme pour les fichiers ca serait long de tout changer pour CreateFile etc.. enfin si c'est la seule solution, je le ferais.

    Donc avec fstream, je n'arrive pas a lui envoyer en parameter de wchar_t, il semble ne pas y avoir la possibilité de le faire (peut être je me trompe)

    Ma question est donc si il est possible d'envoyer un wchar_t en parametre a un fstream, si oui, comment?
    Sinon quel serait la solution pour pouvoir lire ces fichiers à caractère spéciaux?

    Si ce n'est pas clair, ou que vous voulez plus d'information, dites le moi.

    PS: Je suis pour windows sous MinGW

    Merci d'avance!

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Salut,
    Je ne suis vraiment pas sûr de ma réponse mais as-tu essayé avec std::wstring?

  3. #3
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    Bonjour,
    Oui je mets mon "path" (qui contient le caractère spécial) dans un wstring mais si j'essaye de mettre le wstring (.c_str()) en parameter de mon ifstream cela me dit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    main.cpp:126:61: error: no matching function for call to 'std::basic_ifstream<char>::basic_ifstream(const wchar_t*, std::_Ios_Openmode)'
    Idem avec wifstream.

  4. #4
    Membre actif
    Inscrit en
    Mai 2012
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2012
    Messages : 65
    Points : 282
    Points
    282
    Par défaut
    Malheureusement ce n'est pas pris en charge dans le standard (c'est assez dommage je trouve), si tu utilises Visual Studio, il y a un constructeur avec en paramètre un wchar_t, idem pour la fonction open().
    Cela dit c'est spécifique à Visual, GCC (MinGW) et Clang n'ont pas cette spécification à ma connaissance.

    Les choix qui s'offrent à toi :
    1) Tu reste sous le compilo Visual et ton code sera spécifique à Windows et compilable que via Visual

    2) Tu utilises Boost qui gère l'UNICODE ou une bibliothèque équivalente.

    3) Tu utilises fopen (C-like), sous linux les wchar_t sont gérés de base, sous windows, il faudra utiliser wfopen (une macro pour rendre le code portable).

    Quoiqu'il en soit les caractères UNICODE sont mal gérés par le standard, c'est l'un des plus gros point noir de la STL selon moi, obliger d'utiliser des gros framework pour géré ce genre de chose ou alors tout refaire à la main.

  5. #5
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    Effectivement j'ai vu que cela ne sortait pas d'erreur quand j'utilise Boost, mais quand je test l'ouverture du fichier j'ai un invalid argument. Pourtant je passé exactement la même ligne pour le CreateFileW (que j'utilise pour savoir la taille du fichier et qui fonctionne)

    Sauriez-vous pourquoi? (je met un peu de code au cas où c'est une erreur de ma part)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    off_t tailleArborescence(const std::string& chemin){
    	off_t tailleTotal=0, tailleFic=0;
    	std::ifstream fichier(chemin.c_str());
    	std::string ligne;
    	while(getline(fichier,ligne))
    	{
    		// Formatage du nom du fichier
    		std::wstring nomFicUNI = to_unicode(ligne);
     
    		boost::filesystem::fstream file(nomFicUNI.c_str());
    			if(!file){
    				std::cout << "non ta fail" << std::endl;
    				perror("errorboostfile ");
    			}else
    				std::cout << "tes un bon" << std::endl;
     
     
    		tailleFic = sizeFic(nomFicUNI.c_str());
    		tailleTotal = tailleTotal + tailleFic;
    	}
    	fichier.close();
    	return tailleTotal;
    }
    sizeFic va calculer la taille d'un fichier (ou j'utilise CreateFileW pour l'ouvrir) qui fonctionne.


    J'insère dans mon fichier listeFic les noms de fichier comme suit (avec boost):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	for ( boost::filesystem::recursive_directory_iterator end, dir(path);dir != end; ++dir ) {
    		if(boost::filesystem::is_regular_file(dir->status())){	
    			std::ofstream fileFlux(cheminListeFic.c_str() ,std::ios::out | std::ios::app);
    			std::wstring nomDoc = L"\\\\?\\" + dir->path().wstring();
     
    			fileFlux << to_utf8(nomDoc) << std::endl;
    			fileFlux.close();                                    
    		}
    	}

    Ensuite les fonctions pour les différents encodage:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    std::wstring to_unicode(const char* buffer, int len){
    	int nChars = ::MultiByteToWideChar(
    		CP_UTF8,
    		0,
    		buffer,
    		len,
    		NULL,
    		0);
    	if (nChars == 0) return L"";
     
     
    	std::wstring newbuffer;
    	newbuffer.resize(nChars) ;
    	::MultiByteToWideChar(
    		CP_UTF8,
    		0,
    		buffer,
    		len,
    		const_cast< wchar_t* >(newbuffer.c_str()),
    		nChars); 
     
    		return newbuffer;
    }
     
    std::wstring to_unicode(const std::string& str){
       return to_unicode(str.c_str(), (int)str.size());
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    std::string to_utf8(const wchar_t* buffer, int len){
       int nChars = ::WideCharToMultiByte(
          CP_UTF8,
          0,
          buffer,
          len,
          NULL,
          0,
          NULL,
          NULL);
       if (nChars == 0) return "";
     
       std::string newbuffer;
       newbuffer.resize(nChars) ;
       ::WideCharToMultiByte(
          CP_UTF8,
          0,
          buffer,
          len,
          const_cast< char* >(newbuffer.c_str()),
          nChars,
          NULL,
          NULL); 
     
       return newbuffer;
    }
     
    std::string to_utf8(const std::wstring& str){
    	return to_utf8(str.c_str(), (int)str.size());
    }

  6. #6
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Salut,

    J'ai trouvé ce site qui explique comment convertir un char en wchar_t.

    Voici un petit exemple que j'ai fait avec [1]:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
     
    //Ceci est le code du site cité plus haut
    /**
     * Convert a command line parameter, provided as a single character
     * format, into a wide character format.
     *
     * @param[in]  int      argc   Number of parameters available on the command line.
     * @param[in]  char    *argv[] Array of pointers to command line values.
     * @param[out] wchar_t **dst   Destination wide character string.
     * @param[in]  int      index  Command line parameter index to format as wide string.
     * @return     wchar_t *dst    Destination wide character string.
     *   If the specified command line parameter is missing an empty string will be reported.
     */
    wchar_t *AomCommandLineW(int argc, char *argv[], wchar_t **dst, int index) {
    	wchar_t *dst_p;
    	int i = 0;
    	int i_max = 0;
     
    	//dst_p will hold the address of our wide character array.
    	//dst will hold the address of the parameter to redirect to the wide character array.
    	dst_p = *dst;
     
    	// Report a blank wchar_t string on error or null parameter.
    	if ((index >= argc) || (index < 0) || (!argc) || (!argv)) {
    		free(dst_p);
    		dst_p = static_cast<wchar_t*>(malloc(sizeof(wchar_t)));
    		//std::fill(dst_p, dst_p + sizeof(wchar_t), 0);
    		memset(dst_p, 0, sizeof(wchar_t));
    		*dst = dst_p;
    		return dst_p;
    	}
    	i_max = strlen(argv[index]);
     
    	// Free and re-allocate destination memory. Don't forget the terminating null.
    	free(dst_p);
    	dst_p =  static_cast<wchar_t*>(malloc((strlen(argv[index]) * sizeof(wchar_t)) + sizeof(wchar_t)));
     
    	// Copy the string, converting each character as we go. Don't forget the terminating null.
    	for (i = 0; i < i_max; i++) {
    		mbtowc(&dst_p[i], &argv[index][i], sizeof(char));
    	}
    	memset(&dst_p[i], 0, sizeof(wchar_t));
     
    	//Update the destination argument.
    	*dst = dst_p;
    	return dst_p;
    }
     
    int main(int argc, char **argv) {
     
            //Utilisation de la bonne locale
    	setlocale( LC_ALL, "" );
    	if (argc < 2) {
    		std::cout << "Usage: " << argv[0] << " file";
    		exit(1);
    	}
     
            //Conversion char* en wchar_t*
    	wchar_t *dst = NULL;
    	AomCommandLineW(argc, argv, &dst, 1);
     
     
    	std::wstring filename = dst;
     
            //Recopie du wstring dans un string "classique"
    	std::string t(filename.begin(), filename.end());
     
            //Utilisation du string pour ouvrir le fichier
    	std::wifstream wfs(t.c_str());
     
    	std::wstring temp;
     
    	if (!wfs.is_open())
    	{
    		std::cerr << "Error!!!";
    	}
     
    	while (!wfs.eof()) {
    		wfs >> temp;
    		std::wcout << temp;
    	}
     
    	wfs.close();
    }
    J'ai regardé un peu le code de basic_stream et je trouve bizarre que les constructeurs n'utilisent pas le "typename" _CharT:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template<typename _CharT, typename _Traits>
        class basic_ifstream : public basic_istream<_CharT, _Traits>
        {
        public:
          // Types:
          typedef _CharT 					char_type;
     
    //...
     
    public:
    explicit
          basic_ifstream(const char* __s, ios_base::openmode __mode = ios_base::in) //const char* au lieu d'un const char_type *
    Quelqu'un aurait une explication la dessus?


    Edit:[1]: Je viens de tester avec des caractères grecs dans le nom de fichier et l'ouverture ne pose pas de problèmes. Par contre, si j'en mets dans le fichier, ça ne fonctionne pas comme prévu. Je pense qu'il faille à nouveau reconvertir les données reçues.... Je me suis aperçu que mon fichier n'était pas enregistré dans le bon format de fichier.

  7. #7
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    Salut,

    Tu es sous quel environnement ? car j'ai beau essayer ce petit bout de code sous MinGW j'ai toujours Error!!!

    De plus meme minGW n'arrive pas a afficher le caractère et le remplace par un ? lol (j'ai mis le caractère grec γ dans le nom de fichier

  8. #8
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 187
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 187
    Points : 17 135
    Points
    17 135
    Par défaut
    Pour le non-usage de _CharT, à mon avis, c'est une question de sémantique.

    _CharT est le type de caractères lus dans le fichier, qui n'est pas forcément lié au nom du fichier.

    L'OS pose ses contraintes sur le jeu de caractères utilisables pour nommer un fichier.
    Par exemple, windows est insensible à la casse

    De même tu pourrais concevoir un type de xchar ayant les propriétés magiques de ton choix, que tu pourrais tout à fait écrire dans un fichier (qui n'est jamais qu'une suite d'octets).
    tu aurais alors un basic_ifstream<xchar>, dont le nom de fichier serait encore un char*;
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  9. #9
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    J'ai mingw w64 avec G++ 4.8.2. J'ai téléchargé la version avec Qt que j'ai trouvé ici. (Sous windows 7 64 bits)

    Edit: @leternel: c'est vrai que windows ne fait pas attention à la casse pour les noms de fichier mais il accepte les caractères grecs style: ß... On se demande ce qu'ils ont pensé à l'époque ^^ Du coup, je trouve ça quand même étrange qu'il faille faire une conversion pour le nom du fichier alors que l'on pourrait directement avoir le codage fournie lors de l'exécution, non?

  10. #10
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    Bizarre, j'ai gcc 4.8.1 donc je pense pas que cela vient de là, concernant MinGW, quand tu fais un ls sur le fichier avec les caractères grecs, il te les affiche?

  11. #11
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    J'exécute le programme directement dans DOS. Je n'ai pas la commande ls mais dir (et donc ça me les affiches).
    Mais dans une fenêtre MSYS, ça n'affiche pas les bons caractères vu que l'environnement doit être en UTF-8 contrairement à Windows

  12. #12
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    Ah, même avec un dir sous windows (qui est un w7 Pro N SP1) cela ne m'affiche pas le caractère :/

  13. #13
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Tu essaies d'afficher quels caractères? Et surtout, comment tu as créé ce fichier? Perso, j'ai juste fait un clic droit, créé un fichier texte...

  14. #14
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    Salut,
    Pareil clic droit creer fichier txt
    J'essaye d'afficher le caractère "γ" par exemple.

    EDIT: Le ß il l'affiche avec dir et j'arrive aussi a l'ouvrir avec le petit bout de code

  15. #15
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    J'obtiens la même chose avec ton gamma.... C'est vraiment bizarre que l'on puisse lire certains caractères et d'autres non...
    Quel Alt-code as-tu utilisé pour obtenir ton gamma du coup?

  16. #16
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    Je l'ai pris directement dans "charmap" et j'avais tester avec celui sur wiki parce que je n'arrive pas à faire les alt code avec le clavier que j'ai ici lol.

  17. #17
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Points : 718
    Points
    718
    Par défaut
    Je sens que tu vas malheureusement être obligé de passer par ICU ou Boost comme le suggère Danny K.

  18. #18
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    J'ai testé avec boost, et cela ne fonctionne pas il veut bien les wchar_t mais ca ne m'ouvre pas le fichier (à cause du caractère) par contre la j'ai testé avec wfopen et ca a l'air de marcher sans problème. J'ai modifié tout mon code et je test sur une plus grosse arborescence (ou j'avais pas mal d'erreur à cause de ca) et j'ai pas d'erreur pour l'instant.

    Je vous dirais ce que ca donne (surement demain)

  19. #19
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 16
    Points : 4
    Points
    4
    Par défaut
    Bonjour
    Je n'ai plus l'air d'avoir d'erreur de caractères spéciaux avec wfopen, cela me parait bon

    Merci pour ces informations !

Discussions similaires

  1. Réponses: 1
    Dernier message: 24/06/2013, 22h27
  2. Ecriture dans un fichier, caractères spéciaux
    Par mister3957 dans le forum C++
    Réponses: 1
    Dernier message: 18/09/2008, 12h45
  3. Script shell pour enlever les caractères spéciaux d'un nom de fichier
    Par babo dans le forum Shell et commandes GNU
    Réponses: 9
    Dernier message: 12/09/2008, 13h49
  4. Caractère spéciaux dans un nom de fichier
    Par eddie5150 dans le forum Java ME
    Réponses: 6
    Dernier message: 26/06/2008, 14h52
  5. [ZIP] Pb nom fichier caractères spéciaux
    Par ep31 dans le forum Entrée/Sortie
    Réponses: 2
    Dernier message: 05/08/2006, 09h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo