मैं एक संपूर्ण फ़ाइल को std :: string में C ++ में कैसे पढ़ सकता हूं?


178

मैं एक फ़ाइल को एक में कैसे std::stringपढ़ूं, यानी, एक बार में पूरी फ़ाइल कैसे पढ़ूं?

कॉलर द्वारा पाठ या बाइनरी मोड निर्दिष्ट किया जाना चाहिए। समाधान मानक-अनुपालन, पोर्टेबल और कुशल होना चाहिए। इसे स्ट्रिंग के डेटा को अनावश्यक रूप से कॉपी नहीं करना चाहिए, और इसे स्ट्रिंग को पढ़ते समय मेमोरी के पुनरावृत्तियों से बचना चाहिए।

एक तरह से यह करने के लिए फ़ाइल आकार स्टेट के लिए, हो सकता है आकार बदलने std::stringऔर fread()में std::stringकी const_cast<char*>()'एड data()। इसके लिए आवश्यक है कि std::stringडेटा सन्निहित हो जो मानक द्वारा अपेक्षित नहीं है, लेकिन सभी ज्ञात कार्यान्वयनों के लिए ऐसा प्रतीत होता है। क्या होता है, यदि फ़ाइल पाठ मोड में पढ़ी जाती है, तो std::stringफ़ाइल का आकार फ़ाइल के आकार के बराबर नहीं हो सकता है।

एक पूरी तरह से सही है, मानक अनुरूप और पोर्टेबल समाधान का उपयोग कर निर्माण किया जा सकता है std::ifstreamकी rdbuf()एक में std::ostringstreamऔर एक में वहाँ से std::string। हालांकि, यह स्ट्रिंग डेटा और / या अनावश्यक रूप से वास्तविक मेमोरी को कॉपी कर सकता है।

  • सभी प्रासंगिक मानक पुस्तकालय कार्यान्वयन सभी अनावश्यक ओवरहेड से बचने के लिए पर्याप्त स्मार्ट हैं?
  • क्या इसे करने का एक और तरीका है?
  • क्या मुझे कुछ छिपी बूस्ट फंक्शन याद आए जो पहले से ही वांछित कार्यक्षमता प्रदान करता है?


void slurp(std::string& data, bool is_binary)

ध्यान दें कि आपके पास अभी भी कुछ चीजें हैं। उदाहरण के लिए, फ़ाइल का वर्ण एन्कोडिंग क्या है? क्या आप स्वतः पता लगाने का प्रयास करेंगे (जो केवल कुछ विशिष्ट मामलों में काम करता है)? क्या आप सम्मान करेंगे जैसे कि XML हेडर आपको फ़ाइल की एन्कोडिंग बता रहा है? इसके अलावा "टेक्स्ट मोड" या "बाइनरी मोड" जैसी कोई चीज नहीं है - क्या आप एफ़टीपी सोच रहे हैं?
जेसन कोहेन

पाठ और बाइनरी मोड MSDOS और विंडोज विशिष्ट हैक हैं जो इस तथ्य के आसपास जाने की कोशिश करते हैं कि विंडोज (सीआर / एलएफ) में दो वर्णों द्वारा नईलाइनों का प्रतिनिधित्व किया जाता है। पाठ मोड में, उन्हें एक वर्ण ('\ n') माना जाता है।
फेरुचियो

1
हालांकि (काफी) बिल्कुल एक डुप्लिकेट नहीं है, यह बारीकी से संबंधित है: कैसे एक std :: string ऑब्जेक्ट के लिए मेमोरी को पूर्व-आवंटित करना है? (जो ऊपर कोनराड के कथन के विपरीत है, इसमें ऐसा करने के लिए कोड शामिल है, फ़ाइल को गंतव्य में सीधे पढ़कर, बिना अतिरिक्त कॉपी किए)।
जेरी कॉफिन

1
"सन्निहित मानक द्वारा आवश्यक नहीं है" - हाँ यह एक राउंडअबाउट तरीके से है। जैसे ही आप स्ट्रिंग पर op [] का उपयोग करते हैं, इसे एक सन्निहित योग्य बफ़र में समेटा जाना चाहिए, इसलिए यदि आप .resize () पहले पर्याप्त रूप से लिखते हैं, तो इसे & str [0] को लिखना सुरक्षित है। और C ++ 11 में, स्ट्रिंग बस हमेशा सन्निहित है।
तिनो डिड्रिक्सन

2
संबंधित लिंक: C ++ में फाइल कैसे पढ़ें? - बेंचमार्क और विभिन्न दृष्टिकोणों पर चर्चा। और हाँ, rdbuf(स्वीकृत उत्तर में एक) सबसे तेज़ नहीं है, readहै।
लेजेंड्स 2k

जवाबों:


138

एक तरीका एक अलग मेमोरी स्ट्रीम में स्ट्रीम बफर को फ्लश करना है, और फिर उसे std::stringनिम्न में बदलना है :

std::string slurp(std::ifstream& in) {
    std::ostringstream sstr;
    sstr << in.rdbuf();
    return sstr.str();
}

यह अच्छी तरह से संक्षिप्त है। हालाँकि, जैसा कि इस प्रश्न में उल्लेख किया गया है कि यह एक निरर्थक प्रतिलिपि प्रस्तुत करता है और दुर्भाग्य से इस प्रति को खत्म करने का कोई तरीका नहीं है।

एकमात्र वास्तविक समाधान जो निरर्थक प्रतियों से बचा जाता है, पढ़ने को मैन्युअल रूप से लूप में करना है, दुर्भाग्य से। चूंकि C ++ ने अब सन्निहित स्ट्रिंग्स की गारंटी दी है, कोई निम्नलिखित लिख सकता है (14C ++ 14):

auto read_file(std::string_view path) -> std::string {
    constexpr auto read_size = std::size_t{4096};
    auto stream = std::ifstream{path.data()};
    stream.exceptions(std::ios_base::badbit);

    auto out = std::string{};
    auto buf = std::string(read_size, '\0');
    while (stream.read(& buf[0], read_size)) {
        out.append(buf, 0, stream.gcount());
    }
    out.append(buf, 0, stream.gcount());
    return out;
}

20
इसे ऑनलाइनर बनाने की क्या बात है? मैं हमेशा सुपाठ्य कोड का विकल्प चुनूंगा। एक स्व-प्रमाणित VB.Net उत्साही (IIRC) के रूप में मुझे लगता है कि आपको भावना को समझना चाहिए?
sehe

5
@sehe: मैं किसी भी आधे-सक्षम C ++ कोडर को आसानी से समझने की उम्मीद करूंगा कि वह वन-लाइनर है। यह अन्य सामान के आसपास होने की तुलना में बहुत ही प्रसिद्ध है।
DevSolar

43
@DevSolar खैर, अधिक सुपाठ्य संस्करण ~ 30% कम है, कलाकारों की कमी है और अन्यथा समतुल्य है। मेरा सवाल इसलिए खड़ा है: "यह एक oneliner बनाने का क्या मतलब है?"
15

13
नोट: यह विधि फ़ाइल को स्ट्रिंगस्ट्रीम के बफर में पढ़ती है, फिर उस पूरे बफर को कॉपी करती है string। यानी अन्य विकल्पों में से कुछ के रूप में दो बार मेमोरी की आवश्यकता होती है। (बफर को स्थानांतरित करने का कोई तरीका नहीं है)। एक बड़ी फाइल के लिए यह एक महत्वपूर्ण दंड होगा, शायद आवंटन विफलता के कारण भी।
MM

9
@DanNissenbaum आप कुछ भ्रमित कर रहे हैं। प्रोग्रामिंग में वास्तव में महत्वपूर्णता है, लेकिन इसे प्राप्त करने का उचित तरीका यह है कि समस्या को भागों में विघटित किया जाए और उन्हें स्वतंत्र इकाइयों (कार्यों, कक्षाओं, आदि) में समझाया जाए। कार्यों को जोड़ना संगति से अलग नहीं होता है; बिल्कुल इसके विपरीत।
कोनराड रुडोल्फ

52

इसी तरह के सवाल पर यह जवाब देखें ।

आपकी सुविधा के लिए, मैं CTT का समाधान दोहरा रहा हूं:

string readFile2(const string &fileName)
{
    ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate);

    ifstream::pos_type fileSize = ifs.tellg();
    ifs.seekg(0, ios::beg);

    vector<char> bytes(fileSize);
    ifs.read(bytes.data(), fileSize);

    return string(bytes.data(), fileSize);
}

इस समाधान के परिणामस्वरूप यहां प्रस्तुत अन्य उत्तरों की तुलना में लगभग 20% तेजी से निष्पादन समय हुआ, जब मोबी डिक (1.3M) के पाठ के खिलाफ 100 रन का औसत था। पोर्टेबल C ++ समाधान के लिए बुरा नहीं है, मैं फ़ाइल के mmap'ing के परिणाम देखना चाहूंगा;)


3
: संबंधित: विभिन्न तरीकों के समय प्रदर्शन की तुलना में सी में एक बार ++ एक पूरी फाइल में पठन
JFS

12
आज तक, मैंने कभी भी गैर-फाइलिंग परिणामों की रिपोर्ट करने वाले नरग () को नहीं देखा है। बग के स्रोत का पता लगाने के लिए मुझे घंटों लग गए। कृपया फ़ाइल का आकार प्राप्त करने के लिए Tellg () का उपयोग न करें। stackoverflow.com/questions/22984956/…
पुजोमोर क्रोएशिया 0

क्या आपको ifs.seekg(0, ios::end)पहले फोन नहीं करना चाहिए tellg? बस एक फ़ाइल पढ़ने के सूचक को खोलने के बाद शुरुआत में है और इसलिए tellgशून्य
एंड्री Tylychko

1
यह भी आप के रूप में आप भिन्नता करेंगे खाली फ़ाइलों के लिए जांच करने की आवश्यकता nullptrद्वारा&bytes[0]
एंड्री Tylychko

ठीक है, मैं चूक गया हूं ios::ate, इसलिए मुझे लगता है कि स्पष्ट रूप से अंत तक चलने वाला एक संस्करण अधिक पठनीय होगा
एंड्री टायलेको

50

सबसे छोटा संस्करण: Live On Coliru

std::string str(std::istreambuf_iterator<char>{ifs}, {});

इसके लिए हेडर की आवश्यकता होती है <iterator>

कुछ रिपोर्टें थीं कि यह विधि स्ट्रिंग का उपयोग करने और उपयोग करने की तुलना में धीमी है std::istream::read। हालांकि, अनुकूलन के साथ एक आधुनिक संकलक ने सक्षम किया यह अब ऐसा नहीं लगता है, हालांकि विभिन्न तरीकों के सापेक्ष प्रदर्शन अत्यधिक संकलक पर निर्भर लगता है।


7
क्या आप इस उत्तर को छोड़ सकते हैं। यह कितना प्रभावशाली है, क्या यह एक समय में एक फ़ाइल को चार बार पढ़ता है, वैसे भी सरगर्मी स्मृति का प्रचार करने के लिए?
मार्टिन बेकेट

@MM जिस तरह से मैंने उस तुलना को पढ़ा है, यह विधि शुद्ध C ++ पढ़ने-में-एक-प्रचारित-बफर विधि की तुलना में धीमी है।
कोनराड रुडोल्फ

आप सही कह रहे हैं, यह शीर्षक नमूना का एक मामला है, इसके ऊपर कोड के बजाय :) :)
MM

@ ज़ज़लिन सी ++ उस तरह से काम नहीं करता है। किसी विशिष्ट वातावरण में हेडर की आवश्यकता न होना आपके लिए इसे शामिल न करने का एक अच्छा कारण नहीं है।
LF

क्या यह विधि कई बार मेमोरी रीअलोकेशन को ट्रिगर करेगी?
सिक्का

22

उपयोग

#include <iostream>
#include <sstream>
#include <fstream>

int main()
{
  std::ifstream input("file.txt");
  std::stringstream sstr;

  while(input >> sstr.rdbuf());

  std::cout << sstr.str() << std::endl;
}

या कुछ बहुत करीब है। मेरे पास स्वयं को डबल-चेक करने के लिए एक stdlib संदर्भ नहीं है।

हां, मैं समझता हूं कि मैंने slurpफंक्शन को नहीं लिखा ।


यह अच्छा लग रहा है, लेकिन यह संकलन नहीं करता है। इसे संकलित करने के लिए परिवर्तन इसे इस पृष्ठ पर अन्य उत्तरों के लिए कम कर देता है। ideone.com/EyhfWm
JDiMatteo

5
जबकि लूप क्यों?
Zitrax

माना। जब operator>>एक में पढ़ता है std::basic_streambuf, तो यह इनपुट स्ट्रीम का उपभोग करेगा (क्या बचा है), इसलिए लूप अनावश्यक है।
रेमी लेबेउ

15

आप सी ++ 17 (std :: फाइल सिस्टम) है, तो वहाँ भी इस तरह से (जिसके माध्यम से फ़ाइल के आकार हो जाता है std::filesystem::file_sizeके बजाय seekgऔर tellg):

#include <filesystem>
#include <fstream>
#include <string>

namespace fs = std::filesystem;

std::string readFile(fs::path path)
{
    // Open the stream to 'lock' the file.
    std::ifstream f(path, std::ios::in | std::ios::binary);

    // Obtain the size of the file.
    const auto sz = fs::file_size(path);

    // Create a buffer.
    std::string result(sz, '\0');

    // Read the whole file into the buffer.
    f.read(result.data(), sz);

    return result;
}

नोट : आपको उपयोग करने की आवश्यकता हो सकती है <experimental/filesystem>और std::experimental::filesystemयदि आपकी मानक लाइब्रेरी अभी तक C ++ 17 का पूर्ण समर्थन नहीं करती है। तुम भी बदलने के लिए आवश्यकता हो सकती है result.data()के साथ &result[0]करता है, तो इसका समर्थन नहीं करता गैर स्थिरांक std :: basic_string डेटा


1
यह अपरिभाषित व्यवहार का कारण हो सकता है; फ़ाइल को टेक्स्ट मोड में खोलने से कुछ ऑपरेटिंग सिस्टम पर डिस्क फ़ाइल की तुलना में एक अलग स्ट्रीम मिलती है।
MM

1
boost::filesystemयदि आप c ++ 17
Gerhard बर्गर

2
एक एपीआई के साथ एक फ़ाइल खोलना और दूसरे के साथ उसका आकार प्राप्त करना असंगतता और दौड़ की स्थिति के लिए पूछना प्रतीत होता है।
आर्थर टाका

14

उपयोग करने वाली प्रतिक्रियाओं पर सीधे टिप्पणी करने के लिए मेरे पास पर्याप्त प्रतिष्ठा नहीं है tellg()

कृपया ध्यान रखें कि tellg()त्रुटि पर -1 वापस आ सकता है। यदि आप tellg()एक आवंटन पैरामीटर के रूप में परिणाम दे रहे हैं , तो आपको पहले परिणाम की जांच करना चाहिए।

समस्या का एक उदाहरण:

...
std::streamsize size = file.tellg();
std::vector<char> buffer(size);
...

उपरोक्त उदाहरण में, यदि tellg()किसी त्रुटि का सामना करता है तो यह -1 वापस आ जाएगी। हस्ताक्षरित (यानी परिणाम का tellg()) और अहस्ताक्षरित (यानी vector<char>निर्माणकर्ता के लिए arg) के बीच अवैध कास्टिंग आपके वेक्टर में गलती से बहुत बड़ी संख्या में बाइट आवंटित करेगा । (संभवतः 4294967295 बाइट्स, या 4 जीबी।)

उपरोक्त के लिए खाते में संशोधन paxos1977:

string readFile2(const string &fileName)
{
    ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate);

    ifstream::pos_type fileSize = ifs.tellg();
    if (fileSize < 0)                             <--- ADDED
        return std::string();                     <--- ADDED

    ifs.seekg(0, ios::beg);

    vector<char> bytes(fileSize);
    ifs.read(&bytes[0], fileSize);

    return string(&bytes[0], fileSize);
}

5

यह समाधान rdbuf () - आधारित पद्धति में त्रुटि जाँच जोड़ता है।

std::string file_to_string(const std::string& file_name)
{
    std::ifstream file_stream{file_name};

    if (file_stream.fail())
    {
        // Error opening file.
    }

    std::ostringstream str_stream{};
    file_stream >> str_stream.rdbuf();  // NOT str_stream << file_stream.rdbuf()

    if (file_stream.fail() && !file_stream.eof())
    {
        // Error reading file.
    }

    return str_stream.str();
}

मैं यह उत्तर इसलिए जोड़ रहा हूं क्योंकि मूल विधि में त्रुटि-जाँच जोड़ना उतना तुच्छ नहीं है जितना आप अपेक्षा करेंगे। मूल विधि स्ट्रिंगस्ट्रीम के सम्मिलन ऑपरेटर ( str_stream << file_stream.rdbuf()) का उपयोग करती है । समस्या यह है कि यह स्ट्रिंगस्ट्रीम की विफलता को सेट करता है जब कोई वर्ण नहीं डाला जाता है। यह एक त्रुटि के कारण हो सकता है या यह फ़ाइल के खाली होने के कारण हो सकता है। यदि आप असफलता का निरीक्षण करके विफलताओं की जांच करते हैं, तो जब आप एक खाली फ़ाइल पढ़ते हैं, तो आप एक झूठे सकारात्मक का सामना करेंगे। आप किसी भी वर्ण को सम्मिलित करने के लिए वैध विफलता को अस्वीकार करते हैं और किसी भी वर्ण को सम्मिलित करने में "विफलता" करते हैं क्योंकि फ़ाइल खाली है?

आप एक खाली फ़ाइल के लिए स्पष्ट रूप से जाँच करने के लिए सोच सकते हैं, लेकिन यह अधिक कोड और संबंधित त्रुटि जाँच है।

विफलता की स्थिति के लिए जाँच करना str_stream.fail() && !str_stream.eof()काम नहीं करता है, क्योंकि सम्मिलन ऑपरेशन ईओफ़बिट (ओस्ट्रिंगस्ट्रीम पर और न ही इस्ट्रीम) को सेट नहीं करता है।

तो, ऑपरेशन को बदलने के लिए समाधान है। ऑस्ट्रिंगस्ट्रीम के सम्मिलन ऑपरेटर (<<) का उपयोग करने के बजाय, ifstream के निष्कर्षण ऑपरेटर (>>) का उपयोग करें, जो ईबोबिट सेट करता है। फिर विफल स्थिति के लिए जाँच करें file_stream.fail() && !file_stream.eof()

महत्वपूर्ण रूप से, जब file_stream >> str_stream.rdbuf()एक वैध विफलता का सामना करना पड़ता है, तो इसे कभी भी ईबोबिट (विनिर्देश की मेरी समझ के अनुसार) निर्धारित नहीं करना चाहिए। इसका मतलब है कि उपरोक्त जाँच वैध विफलताओं का पता लगाने के लिए पर्याप्त है।


3

इस तरह से कुछ बहुत बुरा नहीं होना चाहिए:

void slurp(std::string& data, const std::string& filename, bool is_binary)
{
    std::ios_base::openmode openmode = ios::ate | ios::in;
    if (is_binary)
        openmode |= ios::binary;
    ifstream file(filename.c_str(), openmode);
    data.clear();
    data.reserve(file.tellg());
    file.seekg(0, ios::beg);
    data.append(istreambuf_iterator<char>(file.rdbuf()), 
                istreambuf_iterator<char>());
}

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


1
आपको इस कोड के संस्करण की जांच करनी चाहिए जो एक स्ट्रिंग के बजाय प्रारंभिक पढ़ने के लिए std :: वेक्टर का उपयोग करता है। बहुत तेज।
paxos1977

3

यथोचित रूप से मजबूत त्रुटि जाँच के साथ नई फ़ाइल सिस्टम लाइब्रेरी का उपयोग करने वाला एक संस्करण है:

#include <cstdint>
#include <exception>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <string>

namespace fs = std::filesystem;

std::string loadFile(const char *const name);
std::string loadFile(const std::string &name);

std::string loadFile(const char *const name) {
  fs::path filepath(fs::absolute(fs::path(name)));

  std::uintmax_t fsize;

  if (fs::exists(filepath)) {
    fsize = fs::file_size(filepath);
  } else {
    throw(std::invalid_argument("File not found: " + filepath.string()));
  }

  std::ifstream infile;
  infile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
  try {
    infile.open(filepath.c_str(), std::ios::in | std::ifstream::binary);
  } catch (...) {
    std::throw_with_nested(std::runtime_error("Can't open input file " + filepath.string()));
  }

  std::string fileStr;

  try {
    fileStr.resize(fsize);
  } catch (...) {
    std::stringstream err;
    err << "Can't resize to " << fsize << " bytes";
    std::throw_with_nested(std::runtime_error(err.str()));
  }

  infile.read(fileStr.data(), fsize);
  infile.close();

  return fileStr;
}

std::string loadFile(const std::string &name) { return loadFile(name.c_str()); };

infile.openके std::stringसाथ परिवर्तित किए बिना भी स्वीकार कर सकते हैं.c_str()
मैट Eding

filepathयह नहीं है std::string, यह एक है std::filesystem::path। पता चला है कि std::ifstream::openउनमें से एक को भी स्वीकार कर सकते हैं।
डेविड जी

@DavidG, std::filesystem::pathस्पष्ट रूप से परिवर्तनीय हैstd::string
जेफरी कैश

Cppreference.com के अनुसार, उस पर ::openसदस्य कार्य std::ifstreamस्वीकार std::filesystem::pathकरता है जैसे कि ::c_str()विधि को पथ पर बुलाया गया था। ::value_typeरास्तों के अंतर्निहित charPOSIX के तहत है।
डेविड जी

2

आप 'std :: getline' फ़ंक्शन का उपयोग कर सकते हैं, और 'eof' को सीमांकक के रूप में निर्दिष्ट कर सकते हैं। परिणामी कोड हालांकि थोड़ा अस्पष्ट है:

std::string data;
std::ifstream in( "test.txt" );
std::getline( in, data, std::string::traits_type::to_char_type( 
                  std::string::traits_type::eof() ) );

5
मैंने अभी-अभी इसका परीक्षण किया है, यह फ़ाइल आकार प्राप्त करने और पूरे फ़ाइल आकार को बफर में पढ़ने की तुलना में बहुत धीमा प्रतीत होता है। 12x धीमे के आदेश पर।
डेविड

यह केवल तब तक काम करेगा, जब तक आपकी फ़ाइल में "eof" (जैसे 0x00, 0xff, ...) वर्ण नहीं हैं। यदि वहाँ हैं, तो आप केवल फ़ाइल का हिस्सा पढ़ेंगे।
ओलाफ डायटशे

2

कभी भी std :: string के const char * बफर में न लिखें। कभी नहीं! ऐसा करना भारी गलती है।

रिज़र्व () आपके std :: string में पूरे स्ट्रिंग के लिए स्थान, उचित आकार की अपनी फ़ाइल से एक बफर में विखंडू पढ़ें, और इसे () जोड़ें। कितना बड़ा हिस्सा होना चाहिए यह आपके इनपुट फ़ाइल आकार पर निर्भर करता है। मुझे पूरा यकीन है कि अन्य सभी पोर्टेबल और एसटीएल-अनुरूप तंत्र भी ऐसा ही करेंगे (फिर भी पहले से दिख सकते हैं)।


5
सी ++ 11 के बाद से std::stringबफर में सीधे लिखने के लिए ठीक होने की गारंटी है ; और मुझे विश्वास है कि इसने इससे पहले सभी वास्तविक कार्यान्वयन पर सही ढंग से काम किया था
MM

1
C ++ 17 के बाद से हमारे पास std::string::data()ट्रिक बफर को सीधे संशोधित करने के लिए गैर-कास्ट विधि है जैसे कि ट्रिक्स का सहारा लिए बिना &str[0]
zett42

@ Zett42 के साथ सहमत यह उत्तर तथ्यात्मक रूप से गलत है
jeremyong

0
#include <string>
#include <sstream>

using namespace std;

string GetStreamAsString(const istream& in)
{
    stringstream out;
    out << in.rdbuf();
    return out.str();
}

string GetFileAsString(static string& filePath)
{
    ifstream stream;
    try
    {
        // Set to throw on failure
        stream.exceptions(fstream::failbit | fstream::badbit);
        stream.open(filePath);
    }
    catch (system_error& error)
    {
        cerr << "Failed to open '" << filePath << "'\n" << error.code().message() << endl;
        return "Open fail";
    }

    return GetStreamAsString(stream);
}

उपयोग:

const string logAsString = GetFileAsString(logFilePath);

0

एक अद्यतन फ़ंक्शन जो सीटीटी के समाधान पर बनाता है:

#include <string>
#include <fstream>
#include <limits>
#include <string_view>
std::string readfile(const std::string_view path, bool binaryMode = true)
{
    std::ios::openmode openmode = std::ios::in;
    if(binaryMode)
    {
        openmode |= std::ios::binary;
    }
    std::ifstream ifs(path.data(), openmode);
    ifs.ignore(std::numeric_limits<std::streamsize>::max());
    std::string data(ifs.gcount(), 0);
    ifs.seekg(0);
    ifs.read(data.data(), data.size());
    return data;
}

दो महत्वपूर्ण अंतर हैं:

tellg()फ़ाइल की शुरुआत के बाद से बाइट्स में ऑफसेट वापस करने की गारंटी नहीं है। इसके बजाय, जैसा कि पुजोमोर क्रोएशिया ने बताया, यह एक टोकन से अधिक है जिसका उपयोग फ़ॉस्ट कॉल के भीतर किया जा सकता है। gcount()हालांकि पिछले निकाले गए बिना विकृत बाइट्स की राशि वापस आती है। इसलिए हम फ़ाइल को खोलते हैं, फ़ाइल ignore()के आकार को प्राप्त करने के लिए इसकी सभी सामग्रियों को निकालते हैं और छोड़ते हैं और उसी के आधार पर आउटपुट स्ट्रिंग का निर्माण करते हैं।

दूसरे, हम एक से फ़ाइल के डेटा की प्रतिलिपि करने से बचने में std::vector<char>एक करने के लिए std::stringस्ट्रिंग सीधे को लिख कर।

प्रदर्शन के मामले में, यह समय के आगे उचित आकार के स्ट्रिंग को आवंटित करने और read()एक बार कॉल करने के लिए, सबसे तेज़ सबसे तेज़ होना चाहिए । एक दिलचस्प तथ्य के रूप में, का उपयोग करते हुए ignore()और countg()के बजाय ateऔर tellg()जीसीसी पर करने के लिए नीचे संकलित लगभग एक ही बात , थोड़ा करके बिट।


1
यह कोड काम नहीं करता है, मुझे खाली स्ट्रिंग मिल रही है। मुझे लगता है कि आप ifs.seekg(0)इसके बजाय चाहते थे ifs.clear()(तब यह काम करता है)।
Xeverous

-1
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
main(){
    fstream file;
    file.open("test.txt");
    string copy,temp;
    while(getline(file,temp)){
        copy+=temp;
        copy+="\n";
    }
    cout<<copy;
    file.close();
}

1
कृपया विवरण जोड़ें।
पीटर

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.