ifstream f;
f.open(fileName);
if ( f.fail() )
{
// I need error message here, like "File not found" etc. -
// the reason of the failure
}
How to get error message as string?
ifstream f;
f.open(fileName);
if ( f.fail() )
{
// I need error message here, like "File not found" etc. -
// the reason of the failure
}
How to get error message as string?
Every system call that fails update the errno
value.
Thus, you can have more information about what happens when a ifstream
open fails by using something like :
cerr << "Error: " << strerror(errno);
However, since every system call updates the global errno
value, you may have issues in a multithreaded application, if another system call triggers an error between the execution of the f.open
and use of errno
.
On system with POSIX standard:
errno is thread-local; setting it in one thread does not affect its value in any other thread.
Edit (thanks to Arne Mertz and other people in the comments):
e.what()
seemed at first to be a more C++-idiomatically correct way of implementing this, however the string returned by this function is implementation-dependant and (at least in G++'s libstdc++) this string has no useful information about the reason behind the error...
e.what()
does not seem to give much information, see updates to my answer. –
Examen errno
uses thread-local storage on modern operating systems. However, there's no guarantee that the fstream
functions will not clobber errno
after an errno occurs. The underlying functions may not set errno
at all (direct system calls on Linux, or Win32). This doesn't work on many real world implementations. –
Gormandize e.what()
always prints the same message "iostream stream error
" –
Topazolite 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'
–
Flirt stderror
thread-safe? –
Rivera You could try letting the stream throw an exception on failure:
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()
, however, does not seem to be very helpful:
strerror(errno)
gives "No such file or directory."If e.what()
does not work for you (I don't know what it will tell you about the error, since that's not standardized), try using std::make_error_condition
(C++11 only):
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)
posted in the comments works and very simple for using. I think that e.what
will work, since errno
works. –
Finesse e.what()
will be what strerror
returns, in a threadsafe way. Both will probably platform dependent. –
Examen exception.what()
. May be a good opportunity to dive into the libstdc++ source code :-) –
Chessa basic_ios::clear
, nothing else. This isn't really helpful. That's why I didn't post ;) –
Reld ios_base::failure
's constructor in the libstdc++ source code.... (i.e. no reference to somthing that looks like errno
) –
Chessa Following on @Arne Mertz's answer, as of C++11 std::ios_base::failure
inherits from system_error
(see http://www.cplusplus.com/reference/ios/ios_base/failure/), which contains both the error code and message that strerror(errno)
would return.
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;
}
This prints No such file or directory.
if fileName
doesn't exist.
iostream stream error
. –
Topazolite iostream error
. What compiler did you test this on? Does any compiler actually provide a user-readable reason for failure? –
Underplay unspecified iostream_category error
. –
Mikkel f.open(fileName)
throws an exception of type std::ios_base::failure
, which is derived from std::system_error
. The exception is caught by the catch block. Within the catch block, e.code()
invokes std::ios_base::failure::code()
which returns an object of type std::error_code
. The error codes defined by class std::error_code
are platform-dependent--i.e., e.code().message()
and e.code().value()
both return platform-dependent values. –
Marciemarcile You can also throw a std::system_error
as shown in the test code below. This method seems to produce more readable output than 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;
}
Example output (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)
The std::system_error
example above is slightly incorrect. std::system_category()
will map the error codes from system's native error code facility. For *nix, this is errno
. For Win32, it is GetLastError()
. ie, on Windows, the above example will print
failed to open C:\path\to\forbidden: The data is invalid
because EACCES is 13 which is the Win32 error code ERROR_INVALID_DATA
To fix it, either use the system's native error code facility, eg on Win32
throw new std::system_error(GetLastError(), std::system_category(), "failed to open"+ filename);
Or use errno and std::generic_category()
, eg
throw new std::system_error(errno, std::generic_category(), "failed to open"+ filename);
throw std::make_shared<std::system_error>(...)
, or even better, throw std::system_error(...)
. –
Patrology © 2022 - 2024 — McMap. All rights reserved.
cerr << "Error code: " << strerror(errno); // Get some info as to why
seems relevant to the question. – Chessastrerror(errno)
works. Post this as answer, I will accept it. – Finesse