c++ tutorial सी++: एसटीडीओटीटी को पुनर्निर्देशित करना




the c++ programming language (6)

मेरे आवेदन में, मैं उस आउटपुट को रीडायरेक्ट करना चाहता हूं जो आमतौर पर एक फ़ंक्शन में stdout स्ट्रीम पर जाता है जिसे मैं परिभाषित करता हूं। मैंने पढ़ा है कि आप एक फ़ाइल में stdio को रीडायरेक्ट कर सकते हैं , तो फ़ंक्शन क्यों नहीं?

उदाहरण के लिए:

void MyHandler( const char* data );

//<<Magical redirection code>>

printf( "test" );
std::cout << "test" << std::endl;

//MyHandler should have been called with "test" twice, at this point
  • मैं इस / समान व्यवहार को कैसे प्राप्त कर सकता हूं?

std::cout ऑब्जेक्ट का एक निश्चित अर्थ है, और यह मानक आउट स्ट्रीम में आउटपुट करना है। आपके प्रोग्राम का उपयोगकर्ता उस नियंत्रण को नियंत्रित करता है जहां मानक आउट कनेक्ट है, न कि आप। आप क्या कर सकते हैं यह तय करना है कि क्या आप फ़ाइल में लिखना चाहते हैं, मानक आउट या किसी अन्य आउटपुट स्ट्रीम में। तो अपने कोड में आप स्विच करते हैं कि आप किस स्ट्रीम को लिखते हैं।

फिर, मानक आउट स्ट्रीम को लिखने का बिंदु उपयोगकर्ता को यह कहने में लचीलापन देना है कि आउटपुट कहां जाता है। आपको मानक आउट रीडायरेक्ट नहीं करना चाहिए; यह ऐसा कुछ है जिसे उपयोगकर्ता को स्वतंत्रता माना जाता है।

एक और बात यह है कि आपको सी ++ प्रोग्राम में सी आईओ और सी ++ आईओ मिश्रण नहीं करना चाहिए। चुनें कि कौन सी आईओ लाइब्रेरी आप काम करना चाहते हैं और इसके साथ चिपके रहें।

उस ने कहा, आप std::basic_istream<> में std::basic_istream<> के टेम्पलेट पैरामीटर पर हैंडलर फ़ंक्शन को टेम्पलेट करके इनपुट लेने के लिए फ़ंक्शन के लिए काफी सुंदर स्विच स्ट्रीम कर सकते हैं। फिर फ़ंक्शन इनपुट स्ट्रीम से अपने इनपुट को वास्तविक प्रकार की धारा से स्वतंत्र रूप से पढ़ेगा जो इसके साथ काम कर रहा है। यहां एक उदाहरण दिया गया है:

#include<iostream>
#include<fstream>
#include<string>

template<class Ch, class Tr>
void dodge_this(std::basic_istream<Ch, Tr>& in)
{
    // in is an input stream. read from it as you read from std::cin.
}

int main(int argc, char* argv[])
{
    if( std::string(argv[1]) == "cin" ) {
        dodge_this(std::cin);
    } else if( std::string(argv[1]) == "file" ) {
        std::ifstream file("input.txt");
        dodge_this(file);
    } else {
        dodge_this(dev_null_stream);  // i just made that up. you get the idea.
    }
}

निम्नलिखित सर्वोत्तम कार्यान्वयन नहीं है, लेकिन इसे अधिकांश आउटपुट के लिए काम करना चाहिए ...

using std::cout;
using std::endl;
using std::string;
using std::stringstream;

class Handler {
        public:
                Handler() {
                };
                virtual ~Handler() {
                };
                void operator<<(string str) {
                        this->stream << str;
                };
                string print(void) {
                        return this->stream.str();
                }
        private:
                stringstream stream;
};

int main(int argc, char ** argv) {
        Handler handle;
        handle << argv[1];
        cout << handle.print() << endl;
        return 0;
}

मैं बस कोशिश करने के लिए नीचे एक छोटा सा मुख्य कार्य डालता हूं और देखता हूं कि यह जिस तरीके से आप चाहते हैं वह काम करता है ..


@ कोनराड रुडॉल्फ सही है, आप आसानी से कम से कम, cout / cerr / clog के लिए यह आसानी से कर सकते हैं। आपको अपने स्वयं के स्ट्रीमबफ कार्यान्वयन की भी आवश्यकता नहीं है, बस एक ostringstream का उपयोग करें।

// Redirect cout.
streambuf* oldCoutStreamBuf = cout.rdbuf();
ostringstream strCout;
cout.rdbuf( strCout.rdbuf() );

// This goes to the string stream.
cout << "Hello, World!" << endl;

// Restore old cout.
cout.rdbuf( oldCoutStreamBuf );

// Will output our Hello World! from above.
cout << strCout.str();

सीर और क्लोग के लिए वही काम काम करता है, लेकिन मेरे अनुभव में जो सामान्य रूप से stdout / stderr के लिए काम नहीं करेगा, इसलिए printf वहां आउटपुट नहीं करेगा। cout stdout पर जाता है, लेकिन cout रीडायरेक्ट सभी stdout पुनर्निर्देशित नहीं करेगा। मुझे ऐसा अनुभव हुआ।

यदि डेटा की मात्रा छोटी होने की उम्मीद है, तो फ्रीपेन / सेटबफ चीज ठीक काम करती है। मैं एक पाइप पर पुनर्निर्देशित fancier डुप्ली / dup2 चीज कर समाप्त हो गया।

अपडेट करें: मैंने एक ब्लॉग पोस्ट लिखा है जिसमें मैंने उपयोग की गई डुप्ली 2 विधि को दिखाया है, जिसे आप here पढ़ सकते हैं। यह ओएस एक्स के लिए लिखा गया है, लेकिन अन्य यूनिक्स स्वादों में काम कर सकता है। मुझे गंभीरता से संदेह है कि यह विंडोज़ में काम करेगा। here एक ही चीज़ का कोको संस्करण।



अन्य सभी उत्तर गलत हैं। आप यह कर सकते हैं, और आपको freopen का सहारा लेने की आवश्यकता नहीं है, न ही किसी अन्य सी या गैर-मानक कार्यों के लिए।

इसके बजाए, आपको अपना स्वयं का std::streambuf कार्यान्वयन, यानी अपना स्वयं का स्ट्रीम बफर बनाना होगा।

एक बार आपके पास हो जाने के बाद, आप बफर को स्विच करके cout स्ट्रीम को रीडायरेक्ट कर सकते हैं:

your_stream_buffer new_buffer;
streambuf* old_buffer = cout.rdbuf(&new_buffer);

cout << "Hello"; // This will be redirected to `new_buffer`.

// Restore original buffer:
cout.rdbuf(old_buffer);

चूंकि मैंने कभी ऐसा नहीं किया है, इसलिए मैं आपको बिल्कुल नहीं बता सकता कि streambuf के कार्यान्वयन को कैसे streambuf है। मेरी सलाह है कि दस्तावेज़ीकरण पर नज़र डालें और एक डमी कार्यान्वयन करें जो सभी कार्यान्वित कार्यों के लिए निदान प्रिंट करता है। यह समझने में मदद करनी चाहिए कि वर्ग कैसे काम करता है।

वैकल्पिक रूप से, अपनी पसंद की सी ++ संदर्भ पुस्तिका देखें जो streambuf क्लास का वर्णन करती है।


आप एक वर्ण सरणी को लिखने के लिए sprintf का उपयोग कर सकते हैं और फिर मान पढ़ सकते हैं:

char buf[1024];
sprintf(buf, "test");
MyHandler(buf);

प्लेटफार्म के आधार पर स्नप्रिंट और कुछ अन्य भी हैं





c++