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:
strerror(errno)
donne "No such file or directory". 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)