ifstream f;
f.open(fileName);
if ( f.fail() )
{
// I need error message here, like "File not found" etc. -
// the reason of the failure
}
如何将错误信息作为字符串获取?
ifstream f;
f.open(fileName);
if ( f.fail() )
{
// I need error message here, like "File not found" etc. -
// the reason of the failure
}
如何将错误信息作为字符串获取?
每个系统调用失败时都会更新errno
的值。
因此,当使用类似于以下内容的语句时,您可以获得更多有关ifstream
打开失败时发生的情况的信息:
cerr << "Error: " << strerror(errno);
然而,由于每一个系统调用都会更新全局的errno
变量,在多线程应用程序中可能会出现问题,如果在执行f.open
和使用errno
之间另一个系统调用触发错误。
在遵循POSIX标准的系统中:
errno
是线程本地的;在一个线程中设置它不会影响其他线程中的值。
编辑(感谢Arne Mertz和其他人的评论):
起初,e.what()
似乎是更符合C++惯用法的实现方式,但该函数返回的字符串是与实现相关的,并且(至少在G++的libstdc++中)此字符串没有关于错误原因的有用信息...
e.what()
似乎没有提供太多信息,请参见我的答案更新。 - Arne Mertzerrno
使用线程本地存储。但是,无法保证在出现 errno
后 fstream
函数不会覆盖 errno
。底层函数可能根本不设置 errno
(在Linux上进行直接系统调用或Win32),这在许多实际实现中并不奏效。 - strcate.what()
总是输出相同的消息"iostream stream error
"。 - rustyxwarning 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'
- sergiol您可以尝试让流在失败时抛出异常:
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()
似乎并没有什么帮助:
strerror(errno)
则返回 "No such file or directory"。如果 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";
}
strerror(errno)
可以工作并且非常简单易用。我认为e.what
会起作用,因为errno
可以工作。 - Alex Fexception.what()
的官方信息。也许这是一个深入研究libstdc++源代码的好机会 :-) - Matthieu Rougetbasic_ios::clear
,没有其他信息。这并不是很有帮助。这就是为什么我没有发布 ;) - arne继@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;
}
如果fileName
不存在,这将打印No such file or directory.
未指定 iostream_category 错误
。 - akimf.open(fileName)
抛出了一个类型为 std::ios_base::failure
的异常,该异常派生自 std::system_error
。异常被 catch 块捕获。在 catch 块内,e.code()
调用 std::ios_base::failure::code()
,返回一个类型为 std::error_code
的对象。类 std::error_code
定义的错误代码是 平台相关 的--即 e.code().message()
和 e.code().value()
都返回平台相关的值。 - Jim Fischer您还可以像下面的测试代码中所示一样抛出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;
}
示例输出(在安装有clang的Ubuntu上):
$ ./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)
std::system_error
示例略有不准确。 std::system_category()
将从系统的本机错误代码库映射错误代码。对于*nix,这是errno
。对于Win32,它是GetLastError()
。即,在Windows上,上面的示例将打印failed to open C:\path\to\forbidden: The data is invalid
由于EACCES是13,这是Win32错误代码ERROR_INVALID_DATA。
要修复它,可以使用系统的本机错误代码功能,例如在Win32上。
throw new std::system_error(GetLastError(), std::system_category(), "failed to open"+ filename);
std::generic_category()
,例如。throw new std::system_error(errno, std::generic_category(), "failed to open"+ filename);
throw std::make_shared<std::system_error>(...)
,或者更好地使用throw std::system_error(...)
。 - undefined
cerr << "Error code: " << strerror(errno); // Get some info as to why
看起来与问题相关。 - Matthieu Rougetstrerror(errno)
可行。将此发布为答案,我会接受它。 - Alex F