ifstream 열기가 실패 할 때 오류 메시지를 얻는 방법


99
ifstream f;
f.open(fileName);

if ( f.fail() )
{
    // I need error message here, like "File not found" etc. -
    // the reason of the failure
}

오류 메시지를 문자열로 얻는 방법?




3
@Alex Farber : 물론입니다. cerr << "Error code: " << strerror(errno); // Get some info as to why질문과 관련이있는 것 같습니다.
마티유 Rouget

@MatthieuRouget : 내가 게시 한 중복 가능성을 확인하십시오. 이것은 gcc에서만 구현 된 비표준 동작 인 것 같습니다.
arne

1
@MatthieuRouget : strerror(errno)작동합니다. 답변으로 게시하면 동의합니다.
Alex F

답변:


72

실패한 모든 시스템 호출은 errno값을 업데이트합니다 .

따라서 ifstream다음과 같은 것을 사용하여 열기가 실패 할 때 발생하는 일에 대한 자세한 정보를 얻을 수 있습니다 .

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

그러나 모든 시스템 호출이 전역 errno값을 업데이트하기 때문에 다른 시스템 호출이의 실행 f.openerrno.

POSIX 표준이있는 시스템에서 :

errno는 스레드 로컬입니다. 한 스레드에서 설정해도 다른 스레드의 값에는 영향을주지 않습니다.


편집 (댓글에 Arne Mertz 및 다른 사람들에게 감사) :

e.what() 처음에는 이것을 구현하는 더 많은 C ++-idiomatically 올바른 방법으로 보였지만이 함수에서 반환 된 문자열은 구현에 따라 다르며 (적어도 G ++의 libstdc ++에서)이 문자열에는 오류의 원인에 대한 유용한 정보가 없습니다.


1
e.what()많은 정보를 제공하지 않는 것 같습니다. 내 답변에 대한 업데이트를 참조하십시오.
Arne Mertz

17
errno최신 운영 체제에서 스레드 로컬 저장소를 사용합니다. 그러나 errno가 발생한 후 fstream함수가 errno중단 되지 않는다는 보장 은 없습니다 . 기본 기능이 전혀 설정되지 않을 수 있습니다 errno(Linux 또는 Win32에서 직접 시스템 호출). 이것은 많은 실제 구현에서 작동하지 않습니다.
strcat 2014 년

1
MSVC에서 e.what()항상 동일한 메시지 " iostream stream error"를 인쇄합니다.
rustyx 2011 년

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'
sergiol

1
@sergiol 거짓말이에요. 무시하거나 경고를 비활성화하십시오.
SS Anne

29

실패시 스트림에서 예외를 throw하도록 할 수 있습니다.

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()그러나별로 도움이되지 않는 것 같습니다.

  • 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 덕분에 ).

에서 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 F

그런 다음 Matthieus 응답에서 멀티 스레딩 대한 annotaions를 참조 - 내 생각은 즉 e.what()무엇을 할 것이다 strerror스레드 세이프 방식으로 반환합니다. 둘 다 아마도 플랫폼에 따라 다릅니다.
Arne Mertz

1
@AlexFarber : Arne의 대답이 저보다 낫다고 생각합니다. 내 솔루션은 문제를 해결 하는 C ++ 방식 이 아닙니다 . 그러나 C ++ 라이브러리가 시스템 호출 오류를 exception.what(). 도 :-) 된 libstdc ++ 소스 코드에 다이빙에 좋은 기회가 될 수 있습니다
마티유 Rouget

나는 이것을 시도했다 : 존재하지 않는 파일을 열려고 시도했지만 예외 메시지는 읽었습니다 basic_ios::clear. 이것은별로 도움이되지 않습니다. 내가 게시되지 않은 이유)
아르네

@arne 어떤 플랫폼, 컴파일러, OS?
Arne Mertz 2013 년

22

@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;
}

존재하지 않는 No such file or directory.경우 인쇄 됩니다 fileName.


9
나를 위해 MSVC 2015에서 iostream stream error.
rustyx

2
나를 위해 GCC 6.3도 인쇄합니다 iostream error. 어떤 컴파일러에서 이것을 테스트 했습니까? 실제로 컴파일러가 사용자가 읽을 수있는 실패 이유를 제공합니까?
Ruslan

2
macOS의 libc ++의 Clang 6 : unspecified iostream_category error.
akim

MacOS 10.14.x의 Xcode 10.2.1 (Clang) / libc ++ (C ++ 17) : "지정되지 않은 iostream_category 오류"도 있습니다. strerror (errno)이 권리를 얻는 유일한 방법 인 것 같습니다. std :: filesystem에 path.exists ()가 있는지 물어보고 반환되는 std :: error_code를 검사하여 먼저 잡을 수 있다고 가정합니다.
SMGreenfield

7

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.