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 whywydaje się mieć znaczenie dla pytania.
strerror(errno)działa. Opublikuj to jako odpowiedź, zaakceptuję to.
Odpowiedzi:
Każde niepowodzenie wywołania systemowego aktualizuje errnowartość.
W ten sposób możesz uzyskać więcej informacji o tym, co się dzieje, gdy ifstreamotwarcie się nie powiedzie, używając czegoś takiego:
cerr << "Error: " << strerror(errno);
Ponieważ jednak każde wywołanie systemowe aktualizuje errnowartość globalną , mogą wystąpić problemy w aplikacji wielowątkowej, jeśli inne wywołanie systemowe wyzwoli błąd między wykonaniem f.opena 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.
errnoużywa magazynu lokalnego wątku w nowoczesnych systemach operacyjnych. Nie ma jednak gwarancji, że fstreamfunkcje nie będą blokować się errnopo wystąpieniu błędu. Podstawowe funkcje mogą errnow 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.whatto zadziała, ponieważ errnodział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::failuredziedziczy 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 fileNamenie 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_errorjak 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)