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 le message d'erreur sous forme de chaîne ?
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 le message d'erreur sous forme de chaîne ?
Chaque appel système qui échoue met à jour le errno
valeur.
Ainsi, vous pouvez avoir plus d'informations sur ce qui se passe lorsqu'une ifstream
l'ouverture échoue en utilisant quelque chose comme :
cerr << "Error: " << strerror(errno);
Toutefois, étant donné que cada L'appel système met à jour les données globales errno
vous risquez d'avoir des problèmes dans une application multithread, si un autre appel système déclenche une erreur entre l'exécution de la fonction f.open
et l'utilisation de errno
.
Sur un système avec la norme POSIX :
errno est thread-local ; le définir dans un thread n'affecte pas sa valeur i affectera pas sa valeur dans un autre thread.
Modifier (merci à Arne Mertz et à d'autres personnes dans les commentaires) :
e.what()
semblait à première vue être une manière plus correcte du point de vue de la nomenclature C++, mais la chaîne de caractères renvoyée par cette fonction dépend de l'implémentation et (au moins dans la libstdc++ de G++) cette chaîne ne contient aucune information utile sur la raison de l'erreur...
Vous pouvez essayer de laisser le flux 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()
ne semble toutefois 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 qu'il vous dira à propos 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 le code d'erreur et le message qui strerror(errno)
reviendrait.
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;
}
Cette impression No such file or directory.
si fileName
n'existe pas.
Vous pouvez également lancer un std::system_error
comme le montre le code de test ci-dessous. Cette méthode semble produire une sortie plus lisible que la méthode 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)
El std::system_error
L'exemple ci-dessus est légèrement incorrect. std::system_category()
mappera les codes d'erreur à partir de la fonction native de code d'erreur du système. Pour *nix, c'est errno
. Pour Win32, c'est GetLastError()
. c'est-à-dire que sous Windows, l'exemple ci-dessus s'imprimera
failed to open C:\path\to\forbidden: The data is invalid
parce que EACCES est 13, ce qui correspond au code d'erreur Win32 ERROR_INVALID_DATA.
Pour le corriger, utilisez le code d'erreur natif du système, par exemple sous Win32.
throw new std::system_error(GetLastError(), std::system_category(), "failed to open"+ filename);
Ou utiliser errno et std::generic_category()
, eg
throw new std::system_error(errno, std::generic_category(), "failed to open"+ filename);
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.