POSIX फ़ाइल डिस्क्रिप्टर से c ++ फ़ॉस्टस्ट का निर्माण कैसे करें?


93

मैं मूल रूप से fdopen () के C ++ संस्करण की तलाश कर रहा हूं। मैंने इस पर थोड़ा शोध किया और यह उन चीजों में से एक है जो ऐसा लगता है कि यह आसान होना चाहिए, लेकिन बहुत जटिल हो जाता है। क्या मुझे इस विश्वास में कुछ याद आ रहा है (अर्थात यह वास्तव में आसान है)? यदि नहीं, तो क्या इससे निपटने के लिए कहीं अच्छी लाइब्रेरी है?

संपादित करें: मेरे उदाहरण के समाधान को एक अलग उत्तर में ले जाया गया।


@Kazark - अब एक अलग जवाब में चले गए, धन्यवाद।
Rivenhill

विंडोज और लिनक्स mmapफ़ाइल में कर सकते हैं और बाइट सरणी के रूप में इसकी सामग्री को उजागर कर सकते हैं ।
eigenfield

जवाबों:


72

Malric Malenfant द्वारा दिए गए उत्तर से:

AFAIK, मानक C ++ में ऐसा करने का कोई तरीका नहीं है। आपके प्लेटफ़ॉर्म के आधार पर, मानक लाइब्रेरी का आपका कार्यान्वयन इनपुट के रूप में फ़ाइल डिस्क्रिप्टर लेते हुए एक फाल्ट कंस्ट्रक्टर के रूप में (एक अमानक एक्सटेंशन के रूप में) पेश कर सकता है। (यह libstdc ++, IIRC के लिए मामला है) या FILE *।

उपरोक्त टिप्पणियों और मेरे शोध के आधार पर नीचे दो वेरिएंट में काम करने वाला कोड है; एक libstdc ++ के लिए और दूसरा Microsoft Visual C ++ के लिए।


libstdc ++

गैर-मानक __gnu_cxx::stdio_filebufवर्ग टेम्पलेट है जो इनहेरिट करता है std::basic_streambufऔर जिसमें निम्न निर्माता हैं

stdio_filebuf (int __fd, std::ios_base::openmode __mode, size_t __size=static_cast< size_t >(BUFSIZ)) 

विवरण के साथ यह निर्माता एक फ़ाइल स्ट्रीम बफर को एक खुले POSIX फ़ाइल डिस्क्रिप्टर के साथ जोड़ता है।

हम इसे POSIX हैंडल (लाइन 1) पास करते हुए बनाते हैं और फिर हम इसे istream के कंस्ट्रक्टर को basic_streambuf (लाइन 2) के रूप में पास करते हैं:

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

using namespace std;

int main()
{
    ofstream ofs("test.txt");
    ofs << "Writing to a basic_ofstream object..." << endl;
    ofs.close();

    int posix_handle = fileno(::fopen("test.txt", "r"));

    __gnu_cxx::stdio_filebuf<char> filebuf(posix_handle, std::ios::in); // 1
    istream is(&filebuf); // 2

    string line;
    getline(is, line);
    cout << "line: " << line << std::endl;
    return 0;
}

Microsoft दृश्य C ++

POSIX फाइल डिस्क्रिप्टर लेने वाले ifstream के कंस्ट्रक्टर का गैर-मानक संस्करण हुआ करता था लेकिन यह वर्तमान डॉक्स और कोड से दोनों गायब है । इफस्ट्रीम के निर्माण का एक और गैर-मानक संस्करण है FILE *

explicit basic_ifstream(_Filet *_File)
    : _Mybase(&_Filebuffer),
        _Filebuffer(_File)
    {   // construct with specified C stream
    }

और यह प्रलेखित नहीं है (मैं किसी भी पुराने दस्तावेज़ को नहीं ढूंढ सका जहाँ यह मौजूद होगा)। हम इसे (लाइन 1) पैरामीटर के साथ बुलाते हैं _ पॉडिक्सन हैंडल से सी स्ट्रीम फ़ाइल * प्राप्त करने के लिए _fdopen को कॉल करने का परिणाम है ।

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

using namespace std;

int main()
{
    ofstream ofs("test.txt");
    ofs << "Writing to a basic_ofstream object..." << endl;
    ofs.close();

    int posix_handle = ::_fileno(::fopen("test.txt", "r"));

    ifstream ifs(::_fdopen(posix_handle, "r")); // 1

    string line;
    getline(ifs, line);
    ifs.close();
    cout << "line: " << line << endl;
    return 0;
}

2
अब पूर्णता के कारण स्वीकृत उत्तर। दूसरों को बढ़ावा देने के उपयोग से मेरे समाधान में दिलचस्पी हो सकती है, जिसे एक अलग उत्तर में ले जाया गया है।
Rivenhill

1
Linux के लिए: यदि आप icc_init.cc को gcc में देखते हैं (स्रोत मेरे पास संस्करण 4.1.1 के लिए है) std :: cout आरंभिक रूप से एक stdio_sync_filebuf <char> को आपके फ़ाइल डिस्क्रिप्टर के चारों ओर आरंभीकृत करके शुरू किया जाता है, तो अपने stdio_sync_filebuf <के आस-पास आंसू पर इनिशियलाइज़िंग करें। चार>। मैं दावा नहीं कर सकता कि यह स्थिर होने जा रहा है।
स्पार्कली

@ स्पार्की std::coutकार्यान्वयन में देखना एक अच्छा विचार है। मैं सोच रहा हूँ क्या बीच का अंतर है stdio_filebufऔर stdio_sync_filebuf?
पायोत्र डोब्रोगोस्ट

MSVC में POSIX fds एमुलेशन हैं। फ़ाइल संचालन के लिए Windows API कई तरीकों से POSIX लोगों से भिन्न होता है - विभिन्न कार्यों के नाम और डेटा प्रकार के पैरामीटर। Windows विभिन्न आंतरिक API ऑब्जेक्ट्स की पहचान करने के लिए आंतरिक रूप से तथाकथित "हैंडल" का उपयोग करता है, और Windows API प्रकार HANDLE को * शून्य के रूप में परिभाषित किया गया है, इसलिए न्यूनतम यह 64-बिट प्लेटफार्मों पर "int" (जो कि 32-बिट) है में फिट नहीं होगा। तो विंडोज के लिए आप उस स्ट्रीम की तलाश में दिलचस्पी ले सकते हैं जो विंडोज एपीआई फ़ाइल हेंडले पर काम करने की अनुमति देता है।
ivan.ukr

40

AFAIK, मानक C ++ में ऐसा करने का कोई तरीका नहीं है। आपके प्लेटफॉर्म के आधार पर, मानक पुस्तकालय का आपका कार्यान्वयन एक गैर-मानक एक्सटेंशन के रूप में एक फ़ाइल डिस्क्रिप्टर लेने वाला एक फ़्लोस्टेर कंस्ट्रक्टर (यह libstdc ++, IIRC के लिए मामला है) या एक FILE*इनपुट के रूप में पेश कर सकता है।

एक और विकल्प एक बढ़ावा का उपयोग करने के लिए होगा :: iostreams :: file_descriptor डिवाइस, जिसे आप एक बढ़ावा में लपेट सकते हैं :: iostreams :: स्ट्रीम यदि आप एक std :: स्ट्रीम इंटरफ़ेस इसके लिए चाहते हैं।


4
यह देखते हुए कि यह एकमात्र पोर्टेबल समाधान है, मुझे समझ में नहीं आता कि यह स्वीकार या शीर्ष-रेटेड उत्तर क्यों नहीं है।
Maarten

8

एक अच्छा मौका है जब आपका कंपाइलर गैर-मानक होने के बावजूद एक FILE- आधारित फ़्लोस्टेर कंस्ट्रक्टर प्रदान करता है। उदाहरण के लिए:

FILE* f = fdopen(my_fd, "a");
std::fstream fstr(f);
fstr << "Greetings\n";

लेकिन जहां तक ​​मुझे पता है, ऐसा करने का कोई पोर्टेबल तरीका नहीं है।


2
ध्यान दें कि g ++ (सही तरीके से) इसे c ++ 11 मोड में अनुमति नहीं देगा
Mark K Cowan

8

इस सवाल के मूल (अस्थिर) प्रेरणा का एक हिस्सा कार्यक्रमों के बीच या सुरक्षित रूप से बनाई गई अस्थायी फ़ाइल का उपयोग करके परीक्षण कार्यक्रम के दो हिस्सों के बीच डेटा पास करने की क्षमता है, लेकिन tmpnam () gcc में चेतावनी फेंकता है, इसलिए वह चाहता था इसके बजाय mkstemp () का उपयोग करने के लिए। यहाँ एक परीक्षण कार्यक्रम है जो मैंने enric Malenfant द्वारा दिए गए उत्तर के आधार पर लिखा है लेकिन fdopen () के बजाय mkstemp () का उपयोग कर रहा है; बूस्ट पुस्तकालयों के साथ मेरी उबंटू प्रणाली पर यह काम करता है:

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>

using boost::iostreams::stream;
using boost::iostreams::file_descriptor_sink;
using boost::filesystem::path;
using boost::filesystem::exists;
using boost::filesystem::status;
using boost::filesystem::remove;

int main(int argc, const char *argv[]) {
  char tmpTemplate[13];
  strncpy(tmpTemplate, "/tmp/XXXXXX", 13);
  stream<file_descriptor_sink> tmp(mkstemp(tmpTemplate));
  assert(tmp.is_open());
  tmp << "Hello mkstemp!" << std::endl;
  tmp.close();
  path tmpPath(tmpTemplate);
  if (exists(status(tmpPath))) {
    std::cout << "Output is in " << tmpPath.file_string() << std::endl;
    std::string cmd("cat ");
    cmd += tmpPath.file_string();
    system(cmd.c_str());
    std::cout << "Removing " << tmpPath.file_string() << std::endl;
    remove(tmpPath);
  }
}

5

यह वास्तव में काफी आसान है। निकोलई एम। जोसुटिस ने fdstreamअपनी पुस्तक द सी ++ स्टैंडर्ड लाइब्रेरी - ए ट्यूटोरियल एंड रेफरेंस के साथ संयोजन में जारी किया है । आप यहां 184 लाइन कार्यान्वयन पा सकते हैं ।


4

मैंने Piotr Dobrogost द्वारा libstdc ++ के लिए ऊपर दिए गए समाधान की कोशिश की है, और पाया कि इसमें एक दर्दनाक दोष था: istream के लिए एक उचित चाल निर्माणकर्ता की कमी के कारण, नवनिर्मित istream ऑब्जेक्ट को बनाना फ़ंक्शन से बाहर निकलना बहुत मुश्किल है । इसके साथ एक और मुद्दा यह है कि यह एक FILE ऑब्जेक्ट (यहां तक ​​कि अंतर्निहित पॉज़िक्स फ़ाइल डिस्क्रिप्टर नहीं सोचा) को लीक करता है। यहाँ एक वैकल्पिक समाधान है जो इन मुद्दों से बचता है:

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

bool OpenFileForSequentialInput(ifstream& ifs, const string& fname)
{
    ifs.open(fname.c_str(), ios::in);
    if (! ifs.is_open()) {
        return false;
    }

    using FilebufType = __gnu_cxx::stdio_filebuf<std::ifstream::char_type>;
    static_assert(  std::is_base_of<ifstream::__filebuf_type, FilebufType>::value &&
                    (sizeof(FilebufType) == sizeof(ifstream::__filebuf_type)),
            "The filebuf type appears to have extra data members, the cast might be unsafe");

    const int fd = static_cast<FilebufType*>(ifs.rdbuf())->fd();
    assert(fd >= 0);
    if (0 != posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
        ifs.close();
        return false;
    }

    return true;
}

Posix_fadvise () के लिए कॉल एक संभावित उपयोग दर्शाता है। यह भी ध्यान दें कि उदाहरण static_assert का उपयोग करता है और जो C ++ 11 का उपयोग कर रहा है, इसके अलावा यह C ++ 03 मोड में ठीक-ठीक निर्माण करना चाहिए।


मूव कंस्ट्रक्टर के उचित संस्करण से आपका क्या तात्पर्य है ? आपने किस संस्करण का प्रयोग किया? हो सकता है कि इस संस्करण में अभी तक कार्यान्वित किए गए मूव कन्स्ट्रक्टर्स नहीं थे - देखें कि क्या इफ्स्टेम का मूव कंस्ट्रक्टर अंतर्निहित रूप से हटा दिया गया है? ?
पायोटर डोब्रोगोस्ट

1
यह एक हैक है जो अंतर्निहित कार्यान्वयन विवरणों पर निर्भर है। मुझे उम्मीद है कि कोई भी कभी भी उत्पादन कोड में इसका उपयोग नहीं करेगा।
डेवमैक

-4

मेरी समझ यह है कि कोड पोर्टेबल रखने के लिए C ++ iostream ऑब्जेक्ट मॉडल में FILE पॉइंटर्स या फ़ाइल डिस्क्रिप्टर के साथ कोई संबंध नहीं है।

उस ने कहा, मैंने कई स्थानों को mds- बर्तनों का उल्लेख करते हुए देखा या उस अंतर को पाटने में मदद करने के लिए बढ़ावा दिया।


9
FILE * मानक C है और इस प्रकार C ++ तो मैं यह नहीं देखता कि C ++ स्ट्रीम के साथ काम करने के लिए C ++ स्ट्रीम पोर्टेबिलिटी को कैसे नुकसान पहुंचा सकता है
Piotr Dobrogost
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.