C++ ifstream 打开失败时如何获取错误消息
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17337602/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get error message when ifstream open fails
提问by Alex F
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?
如何以字符串形式获取错误消息?
采纳答案by Matthieu Rouget
Every system call that fails update the errno
value.
每个失败的系统调用都会更新该errno
值。
Thus, you can have more information about what happens when a ifstream
open fails by using something like :
因此,您可以ifstream
通过使用以下内容获得有关打开失败时会发生什么的更多信息:
cerr << "Error: " << strerror(errno);
However, since everysystem 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
.
但是,由于每个系统调用都会更新全局errno
值,因此在多线程应用程序中可能会遇到问题,如果另一个系统调用f.open
在errno
.
On system with POSIX standard:
在具有 POSIX 标准的系统上:
errno is thread-local; setting it in one thread does not affect its value in any other thread.
errno 是线程本地的;在一个线程中设置它不会影响它在任何其他线程中的值。
Edit(thanks to Arne Mertz and other people in the comments):
编辑(感谢 Arne Mertz 和评论中的其他人):
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()
起初似乎是一种更符合 C++-惯用正确方式的实现方式,但是该函数返回的字符串是依赖于实现的,并且(至少在 G++ 的 libstdc++ 中)该字符串没有关于错误背后原因的有用信息......
回答by Arne Mertz
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:
e.what()
,然而,似乎不是很有帮助:
- I tried it on Win7, Embarcadero RAD Studio 2010 where it gives "ios_base::failbit set" whereas
strerror(errno)
gives "No such file or directory." - On Ubuntu 13.04, gcc 4.7.3 the exception says "basic_ios::clear" (thanks to arne)
- 我在 Win7、Embarcadero RAD Studio 2010 上尝试过,它给出了“ios_base::failbit set”,而
strerror(errno)
给出了“No such file or directory”。 - 在 Ubuntu 13.04、gcc 4.7.3 上,异常显示为“basic_ios::clear”(感谢arne)
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):
如果e.what()
对您不起作用(我不知道它会告诉您什么错误,因为这不是标准化的),请尝试使用std::make_error_condition
(仅限 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";
}
回答by rthur
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.
按照@Arne Mertz 的回答,从 C++11 开始std::ios_base::failure
继承自system_error
(参见http://www.cplusplus.com/reference/ios/ios_base/failure/),其中包含strerror(errno)
将返回的错误代码和消息。
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.
No such file or directory.
如果fileName
不存在,则打印。
回答by ?eurobur?
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(...)
.
您也可以抛出 a std::system_error
,如下面的测试代码所示。这种方法似乎比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):
示例输出(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)