ifstream f;
f.open(fileName);
if ( f.fail() )
{
// I need error message here, like "File not found" etc. -
// the reason of the failure
}
Jak uzyskać komunikat o błędzie w postaci ciągu?
ifstream f;
f.open(fileName);
if ( f.fail() )
{
// I need error message here, like "File not found" etc. -
// the reason of the failure
}
Jak uzyskać komunikat o błędzie w postaci ciągu?
cerr << "Error code: " << strerror(errno); // Get some info as to why
wydaje się mieć znaczenie dla pytania.
strerror(errno)
działa. Opublikuj to jako odpowiedź, zaakceptuję to.
Odpowiedzi:
Każde niepowodzenie wywołania systemowego aktualizuje errno
wartość.
W ten sposób możesz uzyskać więcej informacji o tym, co się dzieje, gdy ifstream
otwarcie się nie powiedzie, używając czegoś takiego:
cerr << "Error: " << strerror(errno);
Ponieważ jednak każde wywołanie systemowe aktualizuje errno
wartość globalną , mogą wystąpić problemy w aplikacji wielowątkowej, jeśli inne wywołanie systemowe wyzwoli błąd między wykonaniem f.open
a użyciem errno
.
W systemie ze standardem POSIX:
errno jest lokalnym wątkiem; ustawienie go w jednym wątku nie wpływa na jego wartość w żadnym innym wątku.
Edytuj (podziękowania dla Arne Mertza i innych osób w komentarzach):
e.what()
początkowo wydawało się, że jest to bardziej C ++ - idiomatycznie poprawny sposób implementacji tego, jednak ciąg zwracany przez tę funkcję jest zależny od implementacji i (przynajmniej w libstdc ++ w G ++) ten ciąg nie zawiera przydatnych informacji o przyczynie błędu ...
e.what()
nie wydaje się udzielać wielu informacji, zobacz aktualizacje mojej odpowiedzi.
errno
używa magazynu lokalnego wątku w nowoczesnych systemach operacyjnych. Nie ma jednak gwarancji, że fstream
funkcje nie będą blokować się errno
po wystąpieniu błędu. Podstawowe funkcje mogą errno
w ogóle nie być ustawione (bezpośrednie wywołania systemowe w systemie Linux lub Win32). To nie działa w wielu rzeczywistych implementacjach.
e.what()
zawsze wypisuje ten sam komunikat " iostream stream error
"
warning C4996: 'strerror': This function or variable may be unsafe. Consider using strerror_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\string.h(168) : see declaration of 'strerror'
Możesz spróbować pozwolić strumieniowi zgłosić wyjątek w przypadku niepowodzenia:
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()
jednak nie wydaje się być zbyt pomocne:
strerror(errno)
daje "No such file or directory".Jeśli e.what()
nie działa dla Ciebie (nie wiem, co powie ci o błędzie, ponieważ nie jest to ustandaryzowane), spróbuj użyć std::make_error_condition
(tylko 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";
}
strerror(errno)
zamieszczone w komentarzach działa i jest bardzo proste w użyciu. Myślę, że e.what
to zadziała, ponieważ errno
działa.
e.what()
będzie to to strerror
, co powróci w sposób bezpieczny dla wątków. Oba będą prawdopodobnie zależne od platformy.
exception.what()
. Może być dobra okazja, aby zagłębić się w kod źródłowy libstdc ++ :-)
basic_ios::clear
, nic więcej. To nie jest naprawdę pomocne. Dlatego nie wysłałem;)
Kontynuując odpowiedź @Arne Mertz, od C ++ 11 std::ios_base::failure
dziedziczy z system_error
(patrz http://www.cplusplus.com/reference/ios/ios_base/failure/ ), który zawiera zarówno kod błędu, jak i komunikat, strerror(errno)
który powróci.
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;
}
To jest drukowane, No such file or directory.
jeśli fileName
nie istnieje.
iostream stream error
.
iostream error
. Na jakim kompilatorze to przetestowałeś? Czy jakikolwiek kompilator faktycznie podaje czytelną dla użytkownika przyczynę niepowodzenia?
unspecified iostream_category error
.
Możesz również rzucić, std::system_error
jak pokazano w kodzie testowym poniżej. Wydaje się, że ta metoda daje bardziej czytelne wyniki niż 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;
}
Przykładowe dane wyjściowe (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)