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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    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
    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
    Par défaut
    Salut,
    Je ne suis vraiment pas sûr de ma réponse mais as-tu essayé avec std::wstring?

  3. #3
    Membre averti
    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
    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 éprouvé
    Inscrit en
    Mai 2012
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2012
    Messages : 65
    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
    Membre averti
    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
    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
    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.

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