2008-09-20 22 views
47

से एक फ़ाइल प्राप्त करना क्या सी ++ std :: fstream से सी फ़ाइल * हैंडल प्राप्त करने के लिए कोई (क्रॉस-प्लेटफॉर्म) तरीका है?एक std :: fstream

कारण मैं पूछता हूं क्योंकि मेरी सी ++ लाइब्रेरी fstreams स्वीकार करती है और एक विशेष कार्य में मैं एक सी लाइब्रेरी का उपयोग करना चाहता हूं जो फ़ाइल * स्वीकार करता है।

उत्तर

31

संक्षिप्त उत्तर नहीं है।

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

असली सवाल यह है कि आप std::fstream ऑब्जेक्ट को FILE* में क्यों परिवर्तित करना चाहते हैं?

हालांकि मैं इसकी अनुशंसा नहीं करता हूं, आप funopen() को देखने का प्रयास कर सकते हैं।
दुर्भाग्यवश, यह एक पॉज़िक्स एपीआई (यह एक बीएसडी एक्सटेंशन है) इसलिए इसकी पोर्टेबिलिटी सवाल में है। जो शायद यह भी है कि मुझे ऐसा कोई नहीं मिला है जिसने std::stream को इस तरह की वस्तु के साथ लपेट लिया है।

FILE *funopen(
       const void *cookie, 
       int (*readfn)(void *, char *, int), 
       int (*writefn)(void *, const char *, int), 
       fpos_t (*seekfn) (void *, fpos_t, int), 
       int (*closefn)(void *) 
      ); 

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

+5

बहुत बुरा यह केवल बीएसडी के लिए है; यह एक अच्छा समाधान होगा क्योंकि यह किसी भी प्रकार की सी ++ स्ट्रीम के साथ एक फ़ाइल * का उपयोग करने की अनुमति देगा। –

+3

आपने पूछा "क्यों?": क्योंकि किसी के पास सी में लिखे गए प्रिंट का सी कार्यान्वयन हो सकता है, जिसे सी ++ ओस्ट्रीम (या ऑफस्ट्रीम) के लिए पुन: उपयोग करना पड़ सकता है। – alfC

+0

क्यों? क्योंकि ऑपरेटर को ओवरलोड करना << बहुत आसान है जब मैं * ऑब्जेक्ट का उपयोग कर रहा हूं, लेकिन स्वरूपण स्ट्रीम आउटपुट गन्दा और दर्दनाक हो सकता है। Fprintf() के साथ स्वरूपण कॉम्पैक्ट और आसान है। दूसरे शब्दों में, मैं 'out << someObject << anotherObject' लिखने में सक्षम होना चाहता हूं लेकिन ऑपरेटर लागू कर सकता हूं << 'fprintf (ofp,"% 8.1lf% 2d \ n ", doubleVar, intVar) का उपयोग करके' – riderBill

4

ठीक है, आप फ़ाइल डिस्क्रिप्टर प्राप्त कर सकते हैं - मैं भूल जाता हूं कि विधि fd() या getfd() है या नहीं। मेरे द्वारा उपयोग किए जाने वाले कार्यान्वयन इस तरह के तरीकों को प्रदान करते हैं, लेकिन भाषा मानक को उनकी आवश्यकता नहीं होती है, मेरा मानना ​​है कि मानक परवाह नहीं करना चाहिए कि आपका प्लेटफ़ॉर्म फ़ाइलों के लिए एफडी का उपयोग करता है या नहीं।

इससे, आप FILE * प्राप्त करने के लिए fdopen (fd, mode) का उपयोग कर सकते हैं।

हालांकि, मुझे लगता है कि एसटीडीआईएन/सीआईएन, एसटीडीओयूटी/सीओटी और एसटीडीईआरआर/सीएआर को सिंक करने के लिए मानक की आवश्यकता वाले तंत्र को आपको दिखाई नहीं देना चाहिए। तो यदि आप दोनों fstream और FILE * का उपयोग कर रहे हैं, तो बफरिंग आपको गड़बड़ कर सकती है।

इसके अलावा, अगर या तो fstream या FILE बंद हो जाता है, तो वे शायद अंतर्निहित एफडी बंद कर देंगे, इसलिए आपको यह सुनिश्चित करने की ज़रूरत है कि आप किसी को बंद करने से पहले दोनों को फ्लश करें।

+1

क्या विधि 'fd() 'या' getfd()' क्या आप मुझे उन्हें इंगित कर सकते हैं? – towi

+0

क्षमा करें, यह इस पर निर्भर करेगा कि आप किस कंपाइलर/लाइब्रेरी का उपयोग कर रहे हैं। libstdC++ के लिए, यह fd() है, ऐसा लगता है: https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_io.html –

+0

गैर पोर्टेबल, एह? अफ़सोस की बात है। – towi

15

कोई मानकीकृत तरीका नहीं है। मुझे लगता है कि ऐसा इसलिए है क्योंकि सी ++ मानकीकरण समूह यह नहीं मानना ​​चाहता था कि फ़ाइल हैंडल को एफडी के रूप में प्रदर्शित किया जा सकता है।

अधिकांश प्लेटफॉर्म ऐसा करने के लिए कुछ गैर-मानक तरीका प्रदान करते हैं।

http://www.ginac.de/~kreckel/fileno/ स्थिति का एक अच्छा लेखन प्रदान करता है और कम से कम जीसीसी के लिए सभी प्लेटफार्म विशिष्ट सकलता को छुपाता है जो कोड प्रदान करता है। यह देखते हुए कि जीसीसी पर यह कितना सकल है, मुझे लगता है कि यदि संभव हो तो मैं इसे सब एक साथ करने से बचूंगा।

+0

ग्रेट लिप्यंतर उस लिंक में, धन्यवाद! –

+3

एक 'फ़ाइल *' और फ़ाइल डिस्क्रिप्टर * अलग * ऑब्जेक्ट्स हैं, और इन्हें विभिन्न घटकों द्वारा उपयोग किया जाता है। एक सी रनटाइम लाइब्रेरी द्वारा उपयोग किया जाता है, दूसरा ओएस द्वारा उपयोग किया जाता है। देखें [फ़ाइल डिस्क्रिप्टर और फ़ाइल पॉइंटर के बीच क्या अंतर है?] (Http://stackoverflow.com/q/2423628) – jww

1

कृपया,, इस पुस्तकालय

MDS utils

यह समस्या हल को देखो क्योंकि एक सी ++ धारा के रूप में एक सी फ़ाइल * इलाज के लिए अनुमति देता है। यह बूस्ट सी ++ पुस्तकालयों का उपयोग करता है।दस्तावेज़ीकरण देखने के लिए आपको डॉक्सीजन का उपयोग करना होगा।

7

अद्यतन: @Jettatura देखें मुझे लगता है कि यह सबसे अच्छा जवाब https://stackoverflow.com/a/33612982/225186 (केवल लिनक्स?) है।

मूल:

(शायद नहीं पार मंच है, लेकिन सरल)

http://www.ginac.de/~kreckel/fileno/ (ड्वोरक जवाब) में हैक Simplifiying, और इस जीसीसी विस्तार http://gcc.gnu.org/onlinedocs/gcc-4.6.2/libstdc++/api/a00069.html#a59f78806603c619eafcd4537c920f859 को देख, मैं इस समाधान है कि काम करता है GCC (4.8 कम से कम) और clang (3.3 कम से कम)

#include<fstream> 
#include<ext/stdio_filebuf.h> 

typedef std::basic_ofstream<char>::__filebuf_type buffer_t; 
typedef __gnu_cxx::stdio_filebuf<char>   io_buffer_t; 
FILE* cfile_impl(buffer_t* const fb){ 
    return (static_cast<io_buffer_t* const>(fb))->file(); //type std::__c_file 
} 

FILE* cfile(std::ofstream const& ofs){return cfile_impl(ofs.rdbuf());} 
FILE* cfile(std::ifstream const& ifs){return cfile_impl(ifs.rdbuf());} 

और सीए पर n इस प्रयोग की जाने वाली,

int main(){ 
    std::ofstream ofs("file.txt"); 
    fprintf(cfile(ofs), "sample1"); 
    fflush(cfile(ofs)); // ofs << std::flush; doesn't help 
    ofs << "sample2\n"; 
} 

सीमाएं: (टिप्पणियों स्वागत कर रहे हैं)

  1. मैं लगता है कि यह std::ofstream को fprintf मुद्रण के बाद fflush के लिए महत्वपूर्ण है, अन्यथा "sample2" पहले दिखाई देने वाला " नमूना 1 "उपर्युक्त उदाहरण में। मुझे नहीं पता कि fflush का उपयोग करने के लिए इसके लिए बेहतर कामकाज है या नहीं। विशेष रूप से ofs << flush मदद नहीं करता है।

  2. फ़ाइल को निकाला नहीं जा सकता * std::stringstream से, मुझे यह भी पता नहीं है कि यह संभव है या नहीं। (एक अद्यतन के लिए नीचे देखें)।

  3. मैं अभी भी कैसे निकालने के लिए पता नहीं है सी stderrstd::cerr आदि से, उदाहरण के fprintf(stderr, "sample") में उपयोग करने के लिए, इस fprintf(cfile(std::cerr), "sample") की तरह एक काल्पनिक कोड में।

    FILE* cfile(std::ostream const& os){ 
        if(std::ofstream const* ofsP = dynamic_cast<std::ofstream const*>(&os)) return cfile(*ofsP); 
        if(&os == &std::cerr) return stderr; 
        if(&os == &std::cout) return stdout; 
        if(&os == &std::clog) return stderr; 
        if(dynamic_cast<std::ostringstream const*>(&os) != 0){ 
         throw std::runtime_error("don't know cannot extract FILE pointer from std::ostringstream"); 
        } 
        return 0; // stream not recognized 
    } 
    FILE* cfile(std::istream const& is){ 
        if(std::ifstream const* ifsP = dynamic_cast<std::ifstream const*>(&is)) return cfile(*ifsP); 
        if(&is == &std::cin) return stdin; 
        if(dynamic_cast<std::ostringstream const*>(&is) != 0){ 
         throw std::runtime_error("don't know how to extract FILE pointer from std::istringstream"); 
        } 
        return 0; // stream not recognized 
    } 
    

    प्रयास iostringstream

    यह का उपयोग कर istream से fscanf के साथ पढ़ने के लिए संभव है संभाल करने के लिए:

पिछले सीमा के बारे में, केवल वैकल्पिक हल मैंने पाया इन भार के जोड़ने के लिए है fmemopen, लेकिन प्रत्येक पढ़ने के बाद स्ट्रीम की इनपुट स्थिति को रखने और अपडेट करने की बहुत सारी किताब की आवश्यकता होती है, अगर कोई सी-रे को जोड़ना चाहता है विज्ञापन और सी ++ - पढ़ता है। मैं इसे उपरोक्त की तरह cfile फ़ंक्शन में परिवर्तित करने में सक्षम नहीं था। (शायद cfileवर्ग जो प्रत्येक पढ़ने के बाद अद्यतन करता रहता है वह रास्ता है)।

// hack to access the protected member of istreambuf that know the current position 
char* access_gptr(std::basic_streambuf<char, std::char_traits<char>>& bs){ 
    struct access_class : std::basic_streambuf<char, std::char_traits<char>>{ 
     char* access_gptr() const{return this->gptr();} 
    }; 
    return ((access_class*)(&bs))->access_gptr(); 
} 

int main(){ 
    std::istringstream iss("11 22 33"); 
    // read the C++ way 
    int j1; iss >> j1; 
    std::cout << j1 << std::endl; 

    // read the C way 
    float j2; 

    char* buf = access_gptr(*iss.rdbuf()); // get current position 
    size_t buf_size = iss.rdbuf()->in_avail(); // get remaining characters 
    FILE* file = fmemopen(buf, buf_size, "r"); // open buffer memory as FILE* 
    fscanf(file, "%f", &j2); // finally! 
    iss.rdbuf()->pubseekoff(ftell(file), iss.cur, iss.in); // update input stream position from current FILE position. 

    std::cout << "j2 = " << j2 << std::endl; 

    // read again the C++ way 
    int j3; iss >> j3; 
    std::cout << "j3 = " << j3 << std::endl; 
} 
+0

यह बहुत अच्छा है! मुझे हाल ही में कुछ tcsetattr() काम करना पड़ा जो कि एक स्ट्रीम के रूप में आया था और आपके लेखन ने वास्तव में मेरी मदद की थी। । –

3

एक एकल पिरोया POSIX आवेदन आप आसानी से एक पोर्टेबल तरह से fd संख्या प्राप्त कर सकते हैं:

int fd = dup(0); 
close(fd); 
// POSIX requires the next opened file descriptor to be fd. 
std::fstream file(...); 
// now fd has been opened again and is owned by file 

एक बहु लड़ी आवेदन में इस विधि टूट जाता है, तो अन्य धागे के साथ इस कोड दौड़ खोलने फाइल डिस्क्रिप्टर।के माध्यम से

#include <boost/iostreams/filtering_stream.hpp> 
#include <boost/iostreams/filter/bzip2.hpp> 
#include <boost/iostreams/device/file.hpp> 

using namespace boost::iostreams; 

int main() 
{ 
    filtering_ostream out; 
    out.push(boost::iostreams::bzip2_compressor()); 
    out.push(file_sink("my_file.txt")); 

    FILE* fp = STDIOAdapter<filtering_ostream>::yield(&out); 
    assert(fp > 0); 

    fputs("Was up, Man", fp); 

    fflush (fp); 

    fclose(fp); 

    return 1; 
} 
2

अभी तक एक और तरीका है Linux में ऐसा करने के लिए:

#include <stdio.h> 
#include <cassert> 

template<class STREAM> 
struct STDIOAdapter 
{ 
    static FILE* yield(STREAM* stream) 
    { 
     assert(stream != NULL); 

     static cookie_io_functions_t Cookies = 
     { 
      .read = NULL, 
      .write = cookieWrite, 
      .seek = NULL, 
      .close = cookieClose 
     }; 

     return fopencookie(stream, "w", Cookies); 
    } 

    ssize_t static cookieWrite(void* cookie, 
     const char* buf, 
     size_t size) 
    { 
     if(cookie == NULL) 
      return -1; 

     STREAM* writer = static_cast <STREAM*>(cookie); 

     writer->write(buf, size); 

     return size; 
    } 

    int static cookieClose(void* cookie) 
    { 
     return EOF; 
    } 
}; // STDIOAdapter 

प्रयोग, उदाहरण के लिए fdopen)। व्यक्तिगत रूप से मुझे FILE* में कोई आवश्यकता नहीं दिखाई देती है, लेकिन फ़ाइल डिस्क्रिप्टर के साथ आप रीडायरेक्टिंग (dup2) जैसी कई रोचक चीजें कर सकते हैं।

समाधान:

#define private public 
#define protected public 
#include <fstream> 
#undef private 
#undef protected 

std::ifstream file("some file"); 
auto fno = file._M_filebuf._M_file.fd(); 

अंतिम स्ट्रिंग libstdc के लिए काम करता ++। यदि आप किसी अन्य लाइब्रेरी का उपयोग कर रहे हैं तो आपको थोड़ा सा रिवर्स-इंजीनियर करना होगा।

यह चाल गंदा है और fstream के सभी निजी और सार्वजनिक सदस्यों का पर्दाफाश करेगी। यदि आप इसे अपने उत्पादन कोड में उपयोग करना चाहते हैं तो मैं आपको एकल के साथ अलग .cpp और .h बनाने का सुझाव देता हूं। शीर्षलेख फ़ाइल में fstream शामिल नहीं होना चाहिए।

+2

बहुत अच्छा, मैं यह 'टेम्पलेट के साथ पूरक <वर्ग स्ट्रीम> फ़ाइल * cfile (स्ट्रीम और रों) { \t वापसी STDIOAdapter :: उपज (&s); }' यह 'std :: cout',' एसटीडी के साथ काम करता है: : cerr' और 'fprintf' और C++ कोड मिलाकर। मैं इसका उपयोग करने की अनुशंसा करता हूं। – alfC

+0

मैं यह पुष्टि करने के लिए फिर से टिप्पणी कर रहा हूं कि यह 'std :: ostringstream' के साथ काम करता है। – alfC

+0

क्या यह' तलाश 'फ़ंक्शन भी समझ में आता है। \t 'पूर्णांक cookieSeek (शून्य * कुकी, ssize_t * बंद, पूर्णांक रास्ता) { \t \t static_cast (कुकी) -> seekg (* बंद, static_cast (कुकी) -> अंत); \t \t वापसी का रास्ता; \t} '? (मुझे यकीन नहीं है कि मैं सही तरीके से 'रास्ता' का उपयोग कर रहा हूं)। – alfC

0

एक तरह से fstream से फ़ाइल वर्णनकर्ता मिलता है और फिर इसे FILE* कन्वर्ट करने के लिए नहीं है (:

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^