ifstream f; f.open(fileName); if ( f.fail() ) { // I need error message here, like "File not found" etc. - // the reason of the failure }
Como obter uma mensagem de erro como string?
Cada chamada de sistema que falha atualiza o valor de errno
.
Assim, você pode ter mais informações sobre o que acontece quando um ifstream
aberto falha usando algo como:
cerr << "Error: " << strerror(errno);
No entanto, uma vez que cada chamada de sistema atualiza o valor global de errno
, você pode ter problemas em um aplicativo multithread, se outra chamada de sistema acionar um erro entre a execução do f.open
e o uso de errno
.
No sistema com padrão POSIX:
errno é thread-local; defini-lo em um segmento não afeta seu valor em qualquer outro segmento.
Edit (obrigado a Arne Mertz e outras pessoas nos comentários):
e.what()
parecia, a princípio, uma maneira mais C ++ - idiomaticamente correta de implementar isto, entretanto a string retornada por essa function é dependente de implementação e (pelo menos na libstdc ++ do G + +) esta string não tem nenhuma informação útil sobre a razão por trás o erro...
Você poderia tentar deixar o stream lançar uma exceção em caso de falha:
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()
, no entanto, não parece ser muito útil:
strerror(errno)
dá "Nenhum tal arquivo ou diretório." Se e.what()
não funciona para você (eu não sei o que ele vai te dizer sobre o erro, já que isso não é padronizado), tente usar std::make_error_condition
(somente C ++ 11):
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"; }
Seguindo a resposta de @Arne Mertz, a partir de C ++ 11 std::ios_base::failure
herda de system_error
(veja http://www.cplusplus.com/reference/ios/ios_base/failure/ ), que contém o erro código e mensagem que strerror(errno)
retornaria.
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; }
Isso imprime No such file or directory.
if fileName
não existe.
Você também pode lançar um std::system_error
como mostrado no código de teste abaixo. Este método parece produzir saída mais legível que f.exception(...)
.
#include // <-- requires this #include #include 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; }
Exemplo de saída (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)