2008-10-12 13 views
55

मैं एक टेक्स्ट फ़ाइल की पूरी सामग्री को std::string ऑब्जेक्ट को C++ के साथ पढ़ना चाहता हूं।सी ++ के साथ एक टेक्स्ट फ़ाइल पढ़ने का सबसे शानदार तरीका क्या है?

अजगर के साथ

, मैं लिख सकते हैं:

text = open("text.txt", "rt").read() 

यह बहुत सरल और सुरुचिपूर्ण है। मुझे बदसूरत सामान से नफरत है, इसलिए मैं जानना चाहता हूं - सी ++ के साथ एक टेक्स्ट फ़ाइल पढ़ने का सबसे शानदार तरीका क्या है? धन्यवाद।

+21

यदि आप बदसूरत सामान से नफरत करते हैं, तो आप सी ++ का बेहतर उपयोग नहीं करते हैं: पी – OregonGhost

+6

लालित्य के बारे में एक नोट, भले ही सबसे सुरुचिपूर्ण iostream समाधान अभी भी आपके लिए बदसूरत प्रतीत होता है, आप बस एक सुंदर समारोह में encapsulate कर सकते हैं ताकि यह आपकी आंखों को चोट नहीं पहुंचाए;) – OregonGhost

+2

'बदसूरत सामान' तर्क के बारे में: 'जबकि (बदसूरत)) encapsulate_more();' –

उत्तर

121

कई मायनों आप चुनते हैं, जिन आप के लिए सबसे खूबसूरत है कर रहे हैं,।

चार * में पढ़ना:

ifstream file ("file.txt", ios::in|ios::binary|ios::ate); 
if (file.is_open()) 
{ 
    file.seekg(0, ios::end); 
    size = file.tellg(); 
    char *contents = new char [size]; 
    file.seekg (0, ios::beg); 
    file.read (contents, size); 
    file.close(); 
    //... do something with it 
    delete [] contents; 
} 
एसटीडी में

:: स्ट्रिंग:

std::ifstream in("file.txt"); 
std::string contents((std::istreambuf_iterator<char>(in)), 
    std::istreambuf_iterator<char>()); 

वेक्टर में < चार >:

std::ifstream in("file.txt"); 
std::vector<char> contents((std::istreambuf_iterator<char>(in)), 
    std::istreambuf_iterator<char>()); 
स्ट्रिंग में

, stringstream का उपयोग कर:

std::ifstream in("file.txt"); 
std::stringstream buffer; 
buffer << in.rdbuf(); 
std::string contents(buffer.str()); 

file.txt सिर्फ एक उदाहरण है, सब कुछ बाइनरी फ़ाइलों के लिए भी ठीक काम करता है, बस सुनिश्चित करें कि आप ifstream कन्स्ट्रक्टर में ios :: बाइनरी का उपयोग करें।

+1

मुझे आपके उत्तर को मुझसे भी बेहतर पसंद है, जो मैं अक्सर कुछ नहीं कहता हूं। बहुत बढ़िया! +1 –

+7

आपको वास्तव में फ़ंक्शन घोषणा के रूप में व्यवहार करने से रोकने के लिए Istreambuf_iterator <> के साथ सामग्री 'कन्स्ट्रक्टर के पहले तर्क के चारों ओर कोष्ठक का एक अतिरिक्त सेट चाहिए। –

+0

@ ग्रेग: धन्यवाद, मैंने इसे अभी तय कर दिया है। –

4

आप "छोटे कोड" की एक निश्चित संपत्ति के रूप में लालित्य की बात करते हैं। यह कुछ हद तक सहायक व्यक्ति है। कुछ लोग कहेंगे कि सभी त्रुटि प्रबंधन को छोड़ना बहुत ही सुरुचिपूर्ण नहीं है। कुछ लोग कहेंगे कि स्पष्ट और कॉम्पैक्ट कोड जो आप तुरंत समझते हैं वह सुरुचिपूर्ण है।

फ़ाइल सामग्री को पढ़ते हुए अपना स्वयं का एक-लाइनर फ़ंक्शन/विधि लिखें, लेकिन इसे सतह के नीचे कठोर और सुरक्षित बनाएं और आप लालित्य के दोनों पहलुओं को कवर करेंगे।

शुभकामनाएँ

/रॉबर्ट

+3

अनुसूचित जाति : लालित्य लालित्य के रूप में है; सुरुचिपूर्ण कोड के विचार भाषा और प्रतिमानों के बीच भिन्न हैं।एक सी ++ प्रोग्रामर क्या रूबी या पायथन प्रोग्रामर के लिए सुरुचिपूर्ण हो सकता है, और इसके विपरीत। – Rob

0

मुझे मिलान के चार * तरीके पसंद हैं, लेकिन std :: string के साथ।


#include <iostream> 
#include <string> 
#include <fstream> 
#include <cstdlib> 
using namespace std; 

string& getfile(const string& filename, string& buffer) { 
    ifstream in(filename.c_str(), ios_base::binary | ios_base::ate); 
    in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit); 
    buffer.resize(in.tellg()); 
    in.seekg(0, ios_base::beg); 
    in.read(&buffer[0], buffer.size()); 
    return buffer; 
} 

int main(int argc, char* argv[]) { 
    if (argc != 2) { 
     cerr << "Usage: this_executable file_to_read\n"; 
     return EXIT_FAILURE; 
    } 
    string buffer; 
    cout << getfile(argv[1], buffer).size() << "\n"; 
} 

(के साथ या ios_base :: द्विआधारी बिना, आप नई-पंक्तियों tranlated या नहीं चाहते हैं पर निर्भर करता है। आप भी getfile बदल सिर्फ एक स्ट्रिंग वापस जाने के लिए कर सकता है, ताकि आप में एक बफर स्ट्रिंग पारित करने के लिए की जरूरत नहीं है । उसके बाद, परीक्षण संकलक प्रतिलिपि बाहर का अनुकूलन करता है, तो जब लौटने को देखने के लिए)

बहरहाल, यह थोड़ा बेहतर लग सकता है (और एक बहुत धीमी हो):।


#include <iostream> 
#include <string> 
#include <fstream> 
#include <cstdlib> 
using namespace std; 

string getfile(const string& filename) { 
    ifstream in(filename.c_str(), ios_base::binary); 
    in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit); 
    return string(istreambuf_iterator<char>(in), istreambuf_iterator<char>()); 
} 

int main(int argc, char* argv[]) { 
    if (argc != 2) { 
     cerr << "Usage: this_executable file_to_read\n"; 
     return EXIT_FAILURE; 
    } 
    cout << getfile(argv[1]).size() << "\n"; 
} 
10

वहाँ another thread इस विषय पर है।

इस धागे से मेरे समाधान (दोनों एक-लाइनर्स):

अच्छा (देखें मिलान की दूसरी समाधान):

string str((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>()); 

और तेजी से:

string str(static_cast<stringstream const&>(stringstream() << ifs.rdbuf()).str()); 
+0

असल में, पहला तेज़ है क्योंकि यह सीधे आईट्रीम बफर पर काम करता है, और बाद वाला पहले पर निर्भर करता है लेकिन कुछ विफलता स्थिति बिट्स जोड़ता है। –

+0

@ t.g। पहला पूर्व आवंटन के बिना स्ट्रिंग बनाने के लिए एक बहुत ही अक्षम प्रति का उपयोग करता है, जिससे बहुत से आवंटन होते हैं। दूसरा प्री-आवंटित आवश्यक आकार का बफर आवंटित करता है। –

+1

मैंने अभी इसे वीसी ++ 10 के साथ परीक्षण किया है। यह वास्तव में निर्भर करता है। यह फ़ाइल आकार पर निर्भर करता है, पहला छोटी फ़ाइलों के लिए तेज़ है और दूसरी बड़ी फ़ाइलों के लिए तेज़ है, जो साबित होता है कि आपने क्या कहा है। –

1

लेकिन सावधान रहना है कि एक सी ++ - स्ट्रिंग (या अधिक ठोस: एक एसटीएल-स्ट्रिंग) एक सी-स्ट्रिंग जितना छोटा होता है, वह मध्यस्थता की लंबाई को पकड़ने में सक्षम होता है - बिलकुल नहीं!

सदस्य max_size() पर एक नज़र डालें जो आपको स्ट्रिंग में अधिकतम वर्णों की संख्या देता है। यह एक कार्यान्वयन निश्चित संख्या है और विभिन्न प्लेटफार्मों के बीच पोर्टेबल नहीं हो सकता है। विजुअल स्टूडियो तारों के लिए लगभग 4 गीगा का मूल्य देता है, अन्य आपको केवल 64k और 64 बिट-प्लेटफार्मों पर दे सकते हैं, यह आपको वास्तव में कुछ बड़ा दे सकता है! यह निर्भर करता है और निश्चित रूप से आप 4gig सीमा तक पहुंचने से पहले लंबे समय तक मेमोरी थकावट के कारण खराब_लोक-अपवाद में भाग लेंगे ...

बीटीडब्ल्यू: max_size() अन्य एसटीएल-कंटेनरों का भी सदस्य है! यह आपको एक निश्चित प्रकार के तत्वों की अधिकतम संख्या देगा (जिसके लिए आपने कंटेनर को कम किया है) जो यह कंटेनर (सैद्धांतिक रूप से) पकड़ने में सक्षम होगा।()
इसके आकार की जाँच करें और सुनिश्चित करें कि यह MAX_SIZE की तुलना में छोटे है - - पकड़ने और प्रक्रिया bad_alloc-अपवाद

और एक और
:

इसलिए, यदि आप unknow मूल आपको चाहिए की एक फ़ाइल से पढ़ रहे हैं बिंदु: आप स्ट्रिंग में फ़ाइल को पढ़ने पर उत्सुक क्यों हैं? मैं इसे आगे बढ़ाने या कुछ करने के द्वारा इसे आगे बढ़ाने की अपेक्षा करता हूं, है ना? तो इसे एक स्ट्रिंग में पढ़ने की बजाय आप इसे स्ट्रिंगस्ट्रीम में भी पढ़ सकते हैं (जो मूल रूप से स्ट्रिंग के लिए केवल कुछ वाक्य रचनात्मक चीनी है) और प्रसंस्करण करते हैं। लेकिन फिर आप सीधे फ़ाइल से प्रसंस्करण भी कर सकते हैं। क्योंकि यदि सही ढंग से प्रोग्राम किया गया है तो स्ट्रिंगस्ट्रीम को बिना किसी फाइलस्ट्रीम द्वारा प्रतिस्थापित किया जा सकता है, i। ई। फ़ाइल द्वारा ही। या किसी अन्य इनपुट स्ट्रीम के साथ-साथ, वे सभी एक ही सदस्य और ऑपरेटरों को साझा करते हैं और इस प्रकार निर्बाध रूप से बदल सकते हैं!

और प्रसंस्करण के लिए: आप भी संकलक द्वारा स्वचालित कर सकते हैं! ई जी मान लीजिए कि आप स्ट्रिंग को टोकननाइज़ करना चाहते हैं। जब एक उचित टेम्पलेट परिभाषित निम्न क्रियाएँ:
- एक फ़ाइल (या एक स्ट्रिंग या किसी अन्य इनपुट स्ट्रीम) से पढ़ना
- एक एसटीएल-कंटेनर
में सभी पाया टोकन धक्का - - सामग्री
Tokenizing टोकन सॉर्ट वर्णानुक्रम
- किसी भी डबल मान को 0- सभी (!!) सी ++ - कोड (एक ही टेम्पलेट को स्वयं और त्रुटि हैंडलिंग को छोड़ दें) में एक ही (!) पंक्ति में प्राप्त किया जा सकता है! यह फ़ंक्शन std :: copy() की केवल एक कॉल है! बस "टोकन इटरेटर" के लिए Google और आपको मेरा क्या मतलब है इसका एक अनुमान मिलेगा। तो यह मुझे एक फ़ाइल से पढ़ने से भी अधिक "सुरुचिपूर्ण" लगता है ...

+0

ध्यान दें, 'max_size()' को 'size_t' के आकार के सापेक्ष परिभाषित किया गया है, जो आपके प्लेटफ़ॉर्म के बिट आकार के सापेक्ष है।यह इस तरह से परिभाषित किया गया है कि स्ट्रिंग को जितना बड़ा हो सके उतना बड़ा हो सके जितना आपका प्लेटफ़ॉर्म पता कर सके। –

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

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