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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:06:13  来源:igfitidea点击:

How to get error message when ifstream open fails

c++error-handlingstreamstd

提问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 errnovalue.

每个失败的系统调用都会更新该errno值。

Thus, you can have more information about what happens when a ifstreamopen fails by using something like :

因此,您可以ifstream通过使用以下内容获得有关打开失败时会发生什么的更多信息:

cerr << "Error: " << strerror(errno);


However, since everysystem call updates the global errnovalue, you may have issues in a multithreaded application, if another system call triggers an error between the execution of the f.openand use of errno.

但是,由于每个系统调用都会更新全局errno值,因此在多线程应用程序中可能会遇到问题,如果另一个系统调用f.openerrno.

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::failureinherits 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 fileNamedoesn't exist.

No such file or directory.如果fileName不存在,则打印。

回答by ?eurobur?

You can also throw a std::system_erroras 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)