Comment obtenir un message d’erreur lorsque ifstream open échoue

ifstream f; f.open(fileName); if ( f.fail() ) { // I need error message here, like "File not found" etc. - // the reason of the failure } 

Comment obtenir un message d’erreur sous forme de chaîne?

    Chaque appel système qui échoue met à jour la valeur errno .

    Ainsi, vous pouvez avoir plus d’informations sur ce qui se passe quand une ouverture ifstream échoue en utilisant quelque chose comme:

     cerr << "Error: " << strerror(errno); 

    Cependant, comme chaque appel système met à jour la valeur globale errno , vous pouvez rencontrer des problèmes dans une application multithread, si un autre appel système déclenche une erreur entre l'exécution de f.open et l'utilisation de errno .

    Sur le système avec la norme POSIX:

    errno est local-thread; le définir dans un thread n'affecte pas sa valeur dans un autre thread.


    Edit (merci à Arne Mertz et autres personnes dans les commentaires):

    e.what() semblait au début être une manière plus correcte de C ++ - mais la chaîne renvoyée par cette fonction dépend de l'implémentation et (au moins dans libstdc ++ de G ++) cette chaîne n'a aucune information utile sur la raison derrière l'erreur...

    Vous pouvez essayer de laisser le stream lancer une exception en cas d’échec:

     std::ifstream f; //prepare f to throw if failbit gets set std::ios_base::iostate exceptionMask = f.exceptions() | std::ios::failbit; f.exceptions(exceptionMask); try { f.open(fileName); } catch (std::ios_base::failure& e) { std::cerr << e.what() << '\n'; } 

    e.what() , cependant, ne semble pas être très utile:

    • Je l'ai essayé sur Win7, Embarcadero RAD Studio 2010 où il donne "ios_base :: failbit set" alors que strerror(errno) donne "No such file or directory".
    • Sous Ubuntu 13.04, gcc 4.7.3 l'exception dit "basic_ios :: clear" (grâce à arne )

    Si e.what() ne fonctionne pas pour vous (je ne sais pas ce que cela vous dira de l'erreur, puisque ce n'est pas standardisé), essayez d'utiliser std::make_error_condition (C ++ 11 uniquement):

     catch (std::ios_base::failure& e) { if ( e.code() == std::make_error_condition(std::io_errc::stream) ) std::cerr << "Stream error!\n"; else std::cerr << "Unknown failure opening file.\n"; } 

    Suite à la réponse de @Arne Mertz, à partir de C ++ 11 std::ios_base::failure hérite de system_error (voir http://www.cplusplus.com/reference/ios/ios_base/failure/ ), qui contient à la fois l’erreur code et message que strerror(errno) renverrait.

     std::ifstream f; // Set exceptions to be thrown on failure f.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { f.open(fileName); } catch (std::system_error& e) { std::cerr << e.code().message() << std::endl; } 

    Cela imprime No such file or directory. si fileName n'existe pas.

    Vous pouvez également lancer un std::system_error comme indiqué dans le code de test ci-dessous. Cette méthode semble produire une sortie plus lisible que f.exception(...) .

     #include  // <-- requires this #include  #include  void process(const std::ssortingng& fileName) { std::ifstream f; f.open(fileName); // after open, check f and throw std::system_error with the errno if (!f) throw std::system_error(errno, std::system_category(), "failed to open "+fileName); std::clog << "opened " << fileName << std::endl; } int main(int argc, char* argv[]) { try { process(argv[1]); } catch (const std::system_error& e) { std::clog << e.what() << " (" << e.code() << ")" << std::endl; } return 0; } 

    Exemple de sortie (Ubuntu w / clang):

     $ ./test /root/.profile failed to open /root/.profile: Permission denied (system:13) $ ./test missing.txt failed to open missing.txt: No such file or directory (system:2) $ ./test ./test opened ./test $ ./test $(printf '%0999x') failed to open 000...000: File name too long (system:36)