একটি পসিক্স ফাইল বর্ণনাকারী থেকে একটি সি ++ fstream কীভাবে তৈরি করবেন?


94

আমি মূলত fdopen () এর C ++ সংস্করণ খুঁজছি। আমি এ নিয়ে কিছুটা গবেষণা করেছিলাম এবং এটি এমন একটি জিনিস যা মনে হয় এটি সহজ হওয়া উচিত, তবে এটি খুব জটিল হতে পারে। আমি কি এই বিশ্বাসের মধ্যে কিছু মিস করছি (অর্থাত্ এটি সত্যিই সহজ)? যদি তা না হয় তবে এটি পরিচালনা করার জন্য কোথাও কোনও ভাল লাইব্রেরি নেই?

সম্পাদনা: আমার উদাহরণ সমাধানটি একটি পৃথক উত্তরে সরানো হয়েছে।


@ কাজার্ক - ধন্যবাদ, এখন একটি পৃথক উত্তরে চলে গেছে।
বিডি বিডিনিউজ টোয়েন্টিফোর ডটকম

উইন্ডোজ এবং লিনাক্স mmapফাইলটি করতে পারে এবং এর সামগ্রীটি বাইট অ্যারে হিসাবে প্রকাশ করতে পারে।
ইগেনফিল্ড

উত্তর:


74

এরিক ম্যালেনফ্যান্টের দেওয়া উত্তর থেকে:

আফাইক, স্ট্যান্ডার্ড সি ++ এ করার কোনও উপায় নেই। আপনার প্ল্যাটফর্মের উপর নির্ভর করে, আপনার স্ট্যান্ডার্ড লাইব্রেরির প্রয়োগটি একটি ইনস্ট্রিপ্ট কনস্ট্রাক্টর ইনপুট হিসাবে একটি ফাইল বর্ণনাকারী গ্রহণ করতে পারে (একটি অমানুষিক এক্সটেনশন হিসাবে) অফার করতে পারে। (এটি libstdc ++, IIRC এর ক্ষেত্রে) বা একটি ফাইল *।

উপরোক্ত পর্যবেক্ষণ এবং নীচে আমার গবেষণার উপর ভিত্তি করে দুটি রূপে ওয়ার্কিং কোড রয়েছে; একটি libstdc ++ এর জন্য এবং অন্যটি মাইক্রোসফ্ট ভিজ্যুয়াল সি ++ এর জন্য।


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) কে পাশ দিয়ে তৈরি করি এবং তারপরে আমরা এটিকে ইসট্রিমের কনস্ট্রাক্টরকে বেসিক_স্ট্রিমবুফ (লাইন 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;
}

মাইক্রোসফ্ট ভিজ্যুয়াল সি ++

POSIX ফাইল বর্ণনাকারী নেওয়ার ক্ষেত্রে ifstream এর কনস্ট্রাক্টরের অ-মানক সংস্করণ ব্যবহৃত হত তবে এটি বর্তমান ডক্স এবং কোড থেকে উভয়ই অনুপস্থিত । যদি আইফ্রিমের কনস্ট্রাক্টর FILE * নিচ্ছে তার আর একটি অ-মানক সংস্করণ রয়েছে

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

এবং এটি নথিভুক্ত করা হয়নি (এমনকি এটি উপস্থিত থাকবে এমন কোনও পুরানো নথিও আমি খুঁজে পাইনি)। আমরা পিসিক্স ফাইল হ্যান্ডেল থেকে সি স্ট্রিম ফাইল * পেতে _fdopen কল করার প্যারামিটারের সাথে এটি (লাইন 1) কল করি call

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

4
সম্পূর্ণতার কারণে এখন গৃহীত উত্তর। অন্যরা বুস্ট ব্যবহার করে আমার সমাধানটিতে আগ্রহী হতে পারে, যা একটি পৃথক উত্তরে চলে গেছে।
বিডি বিসি রিভেনহিল

4
লিনাক্সের জন্য: আপনি যদি জিসিসি-র ios_init.cc দেখুন (আমার কাছে উত্সটি 4.1.1 সংস্করণে রয়েছে) std :: cout আপনার ফাইল বর্ণনাকারীর চারপাশে একটি stdio_sync_filebuf <Char> আরম্ভ করা হয়, তারপরে আপনার stdio_sync_filebuf < চর> আমি দাবি করতে পারি না যদিও এটি স্থিতিশীল হতে চলেছে।
স্পার্কি

@ স্পার্কি std::coutবাস্তবায়নের সন্ধান করা একটি ভাল ধারণা। আমি ভাবছি করছি কি পার্থক্য stdio_filebufএবং stdio_sync_filebuf?
পাইওটর ডব্রোগস্ট

এমএসভিসি-তে পসিক্স এফডিএস অনুকরণ। ফাইল অপারেশনের জন্য উইন্ডোজ এপিআই বিভিন্নভাবে পসিক্সের থেকে পৃথক হয় - বিভিন্ন ফাংশনের নাম এবং প্যারামিটারগুলির ডেটা ধরণের ind উইন্ডোগুলি অভ্যন্তরীণভাবে বিভিন্ন উইন্ডোজ এপিআই বিষয়বস্তু সনাক্ত করতে "হ্যান্ডলস" নামে পরিচিত, এবং উইন্ডোজ এপিআই টাইপ হ্যান্ডলকে অকার্যকর * হিসাবে সংজ্ঞায়িত করা হয়, তাই সর্বনিম্ন এটি 64-বিট প্ল্যাটফর্মগুলিতে "ইনট" (যা 32-বিট) এর সাথে খাপ খায় না। সুতরাং উইন্ডোজের জন্য আপনি স্ট্রিমটি সন্ধান করতে আগ্রহী হতে পারেন যা উইন্ডোজ এপিআই ফাইল হ্যান্ডলে কাজ করতে দেয়।
ivan.ukr

40

আফাইক, স্ট্যান্ডার্ড সি ++ এ করার কোনও উপায় নেই। আপনার প্ল্যাটফর্মের উপর নির্ভর করে, আপনার স্ট্যান্ডার্ড লাইব্রেরির প্রয়োগটি কোনও ফাইল বিবরণকারী (একটি লিবিস্টডিসি ++, আইআইআরসি ক্ষেত্রে এটি) বা একটি FILE*ইনপুট হিসাবে কোনও স্ট্রিম নির্মাতা (অমানুষিক এক্সটেনশন হিসাবে) অফার করতে পারে ।

আরেকটি বিকল্প একটি ব্যবহার করতে হবে বুস্ট :: iostreams :: file_descriptor ডিভাইস রয়েছে, যা আপনি একটি মধ্যে মোড়ানো পারে বুস্ট :: iostreams :: প্রবাহ যদি আপনি এটি একটি এসটিডি :: প্রবাহ ইন্টারফেস থাকতে চাই।


4
এটিই কেবল পোর্টেবল সমাধান বলে বিবেচনা করে আমি বুঝতে পারি না কেন এটি গৃহীত বা শীর্ষ রেট করা উত্তর নয়।
মার্টেন

8

আপনার সংকলকটি একটি স্টাইল-ভিত্তিক fstream নির্মাণকারীর অফার করার একটি ভাল সুযোগ রয়েছে, যদিও এটি মানক নয়। উদাহরণ স্বরূপ:

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

তবে যতদূর আমি জানি, এটি করার মতো কোনও পোর্টেবল উপায় নেই।


4
নোট করুন যে g ++ (সঠিকভাবে) এটি সি ++ 11 মোডে অনুমতি দেবে না
মার্ক কে কোয়ান

8

এই প্রশ্নের মূল (অচলিত) অনুপ্রেরণার অংশটি হল নিরাপদে তৈরি করা অস্থায়ী ফাইল ব্যবহার করে প্রোগ্রামের মধ্যে বা পরীক্ষার প্রোগ্রামের দুটি অংশের মধ্যে ডেটা পাস করার দক্ষতা থাকা, তবে tmpnam () gcc এ একটি সতর্কতা ছুড়ে দেয়, তাই আমি চেয়েছিলাম পরিবর্তে mkstemp () ব্যবহার করতে। এখানে আমি একটি পরীক্ষা প্রোগ্রাম লিখেছি যা আমি এরিক ম্যালেনফ্যান্টের দেওয়া উত্তরের ভিত্তিতে লিখেছি কিন্তু 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

আমি পাইওটর ডব্রোগোস্ট দ্বারা লিবিস্টডিসি ++ এর জন্য প্রস্তাবিত সমাধানটি চেষ্টা করেছি এবং দেখেছি এটির একটি বেদনাদায়ক ত্রুটি রয়েছে: ইসট্রিমের জন্য সঠিকভাবে সরানো কনস্ট্রাক্টরের অভাবের কারণে সদ্য নির্মিত ইসট্রিম অবজেক্টটি তৈরির ফাংশন থেকে বের করা খুব কঠিন difficult । এর সাথে আর একটি সমস্যা এটি একটি ফাইল বস্তু ফাঁস করে (এমনকি অন্তর্নিহিত পিক্সিক্স ফাইল বর্ণনাকারীও ভাবেননি)। এখানে একটি বিকল্প সমাধান যা এই সমস্যাগুলি এড়িয়ে চলে:

#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 () এ কল একটি সম্ভাব্য ব্যবহার দেখায়। এছাড়াও মনে রাখবেন যে উদাহরণটি স্ট্যাটিক_সেটর ব্যবহার করে এবং সি ++ 11 ব্যবহার করে যা সি ++ 03 মোডে ঠিক জরিমানা করা উচিত।


মুভ কনস্ট্রাক্টরের যথাযথ সংস্করণ বলতে কী বোঝ ? আপনি জিসিসির কোন সংস্করণ ব্যবহার করেছেন? সম্ভবত এই সংস্করণটিতে এখনও মুভি কনস্ট্রাক্টর প্রয়োগ করা হয়নি - দেখুন কি ইফস্টিয়ামের মুভ কনস্ট্রাক্টর অন্তর্নিহিতভাবে মুছে ফেলা হয়েছে? ?
পাইওটর ডব্রোগোস্ট

4
এটি এমন একটি হ্যাক যা অন্তর্নিহিত প্রয়োগের বিশদগুলিতে নির্ভর করে। আমি আশা করব যে কেউ কখনও প্রডাকশন কোডে এটি ব্যবহার করে না।
ডেভম্যাক

-4

আমার উপলব্ধি হ'ল কোড পোর্টেবল রাখার জন্য F + পয়েন্টার বা ফাইল বর্ণনাকারীর সাথে সি ++ আইস্ট্রিমে অবজেক্ট মডেলটিতে কোনও সম্পর্ক নেই।

এটি বলেছিল, আমি বেশিরভাগ জায়গাগুলি এমডিএস-ইউজগুলি উল্লেখ করেছি বা এই ফাঁকটি দূর করতে সহায়তা করতে সহায়তা করেছি।


9
ফাইল * স্ট্যান্ডার্ড সি এবং সুতরাং সি ++ সুতরাং আমি দেখতে পাচ্ছি না যে সি স্ট্রিমের সাথে কাজ করতে সি ++ স্ট্রিমগুলি কীভাবে বহনযোগ্যতার ক্ষতি করতে পারে
পাইওটার ডব্রোগোস্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.