इफस्ट्रीम ओपन फेल होने पर एरर मैसेज कैसे मिलेगा


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
@ एलेक्स फारबर: ज़रूर। cerr << "Error code: " << strerror(errno); // Get some info as to whyप्रश्न के लिए प्रासंगिक लगता है।
मैथ्यू रूज

@MatthieuRouget: मेरे द्वारा पोस्ट किए गए संभावित डुप्लिकेट की जांच करें - ऐसा लगता है कि यह गैर-मानक व्यवहार है जो केवल जीसीसी द्वारा लागू किया गया है।
आर्नी

1
@MatthieuRouget: strerror(errno)काम करता है। इसे उत्तर के रूप में पोस्ट करें, मैं इसे स्वीकार करूंगा।
एलेक्स एफ

जवाबों:


72

हर सिस्टम कॉल जो विफल रहता है errnoमान को अपडेट करता है ।

इस प्रकार, आपके पास इस बारे में अधिक जानकारी हो सकती है कि जब किसी ifstreamचीज़ का उपयोग करके एक ओपन फेल होता है, तो क्या होता है :

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

हालाँकि, चूंकि प्रत्येक सिस्टम कॉल वैश्विक errnoमूल्य को अपडेट करता है , इसलिए आपके पास एक मल्टीथ्रेडेड एप्लिकेशन में समस्याएँ हो सकती हैं, यदि किसी अन्य सिस्टम कॉल के निष्पादन f.openऔर उपयोग के बीच कोई त्रुटि हो errno

POSIX मानक के साथ सिस्टम पर:

इरनो थ्रेड-लोकल है; इसे एक धागे में सेट करने से किसी अन्य धागे में इसका मूल्य प्रभावित नहीं होता है।


संपादित करें (टिप्पणी में Arne Mertz और अन्य लोगों के लिए धन्यवाद):

e.what() ऐसा लगता है कि इसे लागू करने का पहला सी + + - मुहावरेदार तरीका है, हालांकि इस फ़ंक्शन द्वारा लौटाए गए स्ट्रिंग कार्यान्वयन-निर्भर हैं और (कम से कम G ++ के libstdc ++ में) इस स्ट्रिंग में त्रुटि के पीछे के कारण के बारे में कोई उपयोगी जानकारी नहीं है ...


1
e.what()अधिक जानकारी देने के लिए प्रतीत नहीं होता है, मेरे उत्तर के लिए अद्यतन देखें।
अर्ने मर्ट्ज़

17
errnoआधुनिक ऑपरेटिंग सिस्टम पर थ्रेड-लोकल स्टोरेज का उपयोग करता है। हालाँकि, इस बात की कोई गारंटी नहीं है कि किसी ग़लती के होने के बाद fstreamकार्य बंद नहीं होंगे errno। अंतर्निहित कार्य बिल्कुल भी सेट नहीं हो सकते हैं errno(लिनक्स पर प्रत्यक्ष प्रणाली कॉल, या Win32)। यह कई वास्तविक दुनिया कार्यान्वयन पर काम नहीं करता है।
स्ट्रकैट

1
MSVC में, e.what()हमेशा एक ही संदेश प्रिंट करता है " iostream stream error"
rustyx

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'
सर्गियोल

1
@sergiol वे झूठ हैं। उन्हें अनदेखा करें या चेतावनी को अक्षम करें।
एसएस ऐनी

29

आप असफलता पर धारा को फेंक देने की कोशिश कर सकते हैं:

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)देता है, जबकि "ऐसी कोई फ़ाइल या निर्देशिका नहीं देता है।"
  • उबंटू 13.04 पर, जीसीसी 4.7.3 अपवाद कहते हैं, "basic_ios :: स्पष्ट" (धन्यवाद करने के लिए आर्नी )

अगर 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काम करता है।
एलेक्स एफ

फिर मैथियस के उत्तर में मल्टीथ्रेडिंग के बारे में एनोटेशन देखें - मेरा अनुमान है कि e.what()यह वही होगा strerror, जो थ्रेडसेफ़ तरीके से देता है। दोनों शायद मंच पर निर्भर होंगे।
अर्ने मर्ट्ज़

1
@AlexFarber: मुझे लगता है कि अर्ने का जवाब मेरी तुलना में बेहतर है। मेरा समाधान आपकी समस्या को हल करने का तरीका C ++ नहीं है । हालाँकि, मुझे इस बारे में आधिकारिक जानकारी नहीं मिली कि C ++ लाइब्रेरी मैप्स सिस्टम कॉल एरर्स कैसे होता है exception.what()। Libstdc ++ स्रोत कोड में गोता लगाने का एक अच्छा अवसर हो सकता है :-)
Matthieu Rouget

मैंने इसे आज़माया: एक नॉन-सोर्सिंग फ़ाइल खोलने की कोशिश की और अपवाद संदेश पढ़ा basic_ios::clear, और कुछ नहीं। यह वास्तव में उपयोगी नहीं है। यही कारण है कि मैं पद नहीं किया है;)
आर्नी

@arne wich प्लेटफॉर्म, कंपाइलर, ओएस?
अर्ने मर्ट्ज़

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मौजूद नहीं है।


8
मेरे लिए MSVC 2015 में जो सिर्फ प्रिंट करता है iostream stream error
rustyx

2
मेरे लिए जीसीसी 6.3 भी प्रिंट करता है iostream error। आपने इस पर कौन सा संकलक परीक्षण किया? क्या कोई संकलक वास्तव में विफलता के लिए एक उपयोगकर्ता-पठनीय कारण प्रदान करता है?
रुस्लान

2
MacOS पर libc ++ पर क्लेंग 6 unspecified iostream_category error:।
एकिम

MacOS 10.14.x पर Xcode 10.2.1 (Clang) / libc ++ (C ++ 17): "अनिर्दिष्ट iostream_category त्रुटि" भी। strerror (इरनो) SEEMS इस अधिकार को प्राप्त करने का एकमात्र तरीका है। मुझे लगता है कि मैं इसे पहले पूछ सकता हूँ std :: filesystem से पूछें अगर path.exists (), और std की जाँच कर रहा है :: error_code यह रिटर्न करता है।
एसएमग्रीनफील्ड

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

उदाहरण आउटपुट (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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.