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 lorsqu’un ifstream
open échoue en utilisant quelque chose comme:
cerr << "Error: " << strerror(errno);
Cependant, étant donné que chaque appel système met à jour la valeur globale errno
, des problèmes peuvent survenir dans une application multithread, si un autre appel système déclenche une erreur entre l'exécution du f.open
et l'utilisation de errno
.
Sur un système avec la norme POSIX:
errno est thread-local; le placer dans un thread n'affecte pas sa valeur dans aucun autre thread.
Edit (merci à Arne Mertz et à d’autres personnes dans les commentaires):
e.what()
semblait au début être une manière plus correcte d'implémenter ceci, cependant la chaîne renvoyée par cette fonction dépend de l'implémentation et (au moins dans libstdc ++ de G ++), cette chaîne ne contient aucune information utile sur la raison derrière l'erreur ...
Vous pouvez essayer de laisser le flux générer 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()
ne semble toutefois pas très utile:
strerror(errno)
donne "Aucun fichier ni répertoire de ce type". "Si e.what()
ne fonctionne pas pour vous (je ne sais pas ce qu'il vous dira à propos de l'erreur, puisque ce n'est pas normalisé), 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 le code d'erreur et le 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;
}
Ceci affiche 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 <exception> // <-- requires this
#include <fstream>
#include <iostream>
void process(const std::string& 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)