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);
ただし、everyシステムコールはグローバルerrno
値を更新するため、別のシステムコールがエラーをトリガーする場合、マルチスレッドアプリケーションで問題が発生する可能性があります。 f.open
の実行とerrno
の使用の間。
POSIX標準のシステムでは:
errnoはスレッドローカルです。あるスレッドに設定しても、他のスレッドの値には影響しません。
編集(コメントのArne Mertzおよび他の人々に感謝):
e.what()
は最初はこれを実装するよりC++の形式的に正しい方法であるように見えましたが、この関数によって返される文字列は実装に依存し、(少なくともG ++のlibstdc ++では)この文字列には背後の理由に関する有用な情報がありませんエラー...
失敗時にストリームに例外をスローさせることができます:
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";
}
@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.
を出力します。
次のテストコードに示すように、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;
}
出力例(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)