2008-09-25 10 views
30

किसी फ़ाइल से प्रदर्शन पढ़ने में सुधार करने के लिए, मैं स्मृति में एक बड़ी (कई एमबी) फ़ाइल की पूरी सामग्री को पढ़ने की कोशिश कर रहा हूं और फिर जानकारी तक पहुंचने के लिए एक आईटिंगस्ट्रीम का उपयोग कर रहा हूं।istringstream में फ़ाइल सामग्री को कैसे पढ़ा जाए?

मेरा प्रश्न है, इस जानकारी को पढ़ने और स्ट्रिंग स्ट्रीम में "इसे आयात" करने का सबसे अच्छा तरीका कौन सा है? इस दृष्टिकोण के साथ एक समस्या (देखें) यह है कि जब स्ट्रिंग स्ट्रीम बनाते हैं तो बफर कॉपी हो जाते हैं, और मेमोरी उपयोग युगल होता है।

#include <fstream> 
#include <sstream> 

using namespace std; 

int main() { 
    ifstream is; 
    is.open (sFilename.c_str(), ios::binary); 

    // get length of file: 
    is.seekg (0, std::ios::end); 
    long length = is.tellg(); 
    is.seekg (0, std::ios::beg); 

    // allocate memory: 
    char *buffer = new char [length]; 

    // read data as a block: 
    is.read (buffer,length); 

    // create string stream of memory contents 
    // NOTE: this ends up copying the buffer!!! 
    istringstream iss(string(buffer)); 

    // delete temporary buffer 
    delete [] buffer; 

    // close filestream 
    is.close(); 

    /* ================================== 
    * Use iss to access data 
    */ 

} 
+2

आपको डेटा कॉपी करना पसंद है। 1) बफर में कॉपी करें। 2) अज्ञात std :: स्ट्रिंग में कॉपी करें। 3) जारी करने में कॉपी करें। –

+0

शायद आपको इसके बजाय स्मृति मैप की गई फ़ाइलों में खोजना चाहिए। –

उत्तर

32

std::ifstream एक विधि rdbuf(), कि एक filebuf के लिए सूचक रिटर्न है। टिप्पणी में मार्टिन यॉर्क में टिप्पणी, इस के बाद से stringstream के operator<< चरित्र द्वारा filebuf चरित्र पढ़ा जाएगा सबसे तेजी से समाधान नहीं हो सकता है के रूप में: तब आप अपने stringstream में इस filebuf "धक्का" कर सकते हैं:

int main() 
{ 
    std::ifstream file("myFile"); 

    if (file) 
    { 
     std::stringstream buffer; 

     buffer << file.rdbuf(); 

     file.close(); 

     // operations on the buffer... 
    } 
} 

संपादित करें। हो सकता है कि आप उसका जवाब देखना चाहें, जहां वह ifstream की read विधि का उपयोग करता है जैसा कि आप करते थे, और उसके बाद stringstream बफर को पहले आवंटित स्मृति को इंगित करने के लिए सेट करें।

+0

हाय ल्यूक, मैं आपके सुझाव के साथ सहमत हूं ... rdbuf का हेरफेर जाने का रास्ता है! लेकिन क्या आपके समाधान में एक ही समस्या नहीं है? क्या आप कम से कम क्षणिक बफर की 2 प्रतियां नहीं बनाते? –

+6

क्योंकि ऑपरेटर द्वारा <<() rdbuf() के परिणाम को देखता है, यह सिर्फ एक स्ट्रीम बफर है, इस बिंदु पर फ़ाइल बफर की कोई अवधारणा नहीं है, यह इसकी लंबाई नहीं देख सकती है और इस प्रकार 1 को पढ़ने के लिए लूप का उपयोग करना चाहिए एक समय में चार। स्ट्रिंगस्ट्रीम आंतरिक बफर (std :: string) को डेटा के रूप में आकार के रूप में आकार दिया जाना चाहिए। –

+0

ऐसा लगता है कि मुझे नई लाइन वर्णों को हटाया जा रहा है, जो मुझे चाहिए। – Michele

1

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

0

ध्यान में रखना एक और बात यह है कि फ़ाइल I/O हमेशा धीमा ऑपरेशन होने जा रहा है। ल्यूक टौराइल का समाधान सही है, लेकिन अन्य विकल्प भी हैं। पूरी फाइल को स्मृति में एक बार में पढ़ना अलग-अलग पढ़ने से बहुत तेज़ होगा।

40

ठीक है। मैं यह नहीं कह रहा हूं कि यह फ़ाइल

पर पढ़ने से तेज़ होगा, लेकिन यह एक तरीका है जहां आप बफर में डेटा को पढ़ते समय बफर बनाते हैं और स्ट्रिंगस्ट्रीम के स्रोत के रूप में इसे सीधे उपयोग करते हैं।

एनबी। यह उल्लेखनीय है कि std :: ifstream buffered है। यह फ़ाइल (डेटा अपेक्षाकृत बड़े) में डेटा से डेटा पढ़ता है। स्ट्रीम ऑपरेशन बफर के खिलाफ किया जाता है जब अधिक डेटा की आवश्यकता होती है तो केवल एक और पढ़ने के लिए फ़ाइल पर लौट आती है। तो स्मृति में सभी डेटा चूसने से पहले कृपया सत्यापित करें कि यह एक बोतल गर्दन है।

#include <fstream> 
#include <sstream> 
#include <vector> 

int main() 
{ 
    std::ifstream  file("Plop"); 
    if (file) 
    { 
     /* 
     * Get the size of the file 
     */ 
     file.seekg(0,std::ios::end); 
     std::streampos   length = file.tellg(); 
     file.seekg(0,std::ios::beg); 

     /* 
     * Use a vector as the buffer. 
     * It is exception safe and will be tidied up correctly. 
     * This constructor creates a buffer of the correct length. 
     * 
     * Then read the whole file into the buffer. 
     */ 
     std::vector<char>  buffer(length); 
     file.read(&buffer[0],length); 

     /* 
     * Create your string stream. 
     * Get the stringbuffer from the stream and set the vector as it source. 
     */ 
     std::stringstream  localStream; 
     localStream.rdbuf()->pubsetbuf(&buffer[0],length); 

     /* 
     * Note the buffer is NOT copied, if it goes out of scope 
     * the stream will be reading from released memory. 
     */ 
    } 
} 
+3

@ मार्टिन यॉर्क, आप इन विवरणों को कैसे सीखते हैं, क्या आप पढ़ते हैं या जब आप किसी समस्या का सामना करते हैं तो आप शोध करते हैं और बदले में आप इन सभी विवरणों को सीखते हैं? बहुत बहुत धन्यवाद, बीडीडब्ल्यू। –

+3

@ गॉलम: नहीं, यह सिर्फ दो क्षेत्रों से प्राप्त विवरण है। 1) स्ट्रीम कक्षाओं का हर समय उपयोग करना। 2) अपनी खुद की धारा कक्षाओं को लागू करने के बाद। संख्या (2) आपको स्ट्रीम के काम करने के तरीके के बारे में बहुत कुछ पढ़ती है, क्योंकि आप चाहते हैं कि यह आपकी स्ट्रीम के लिए उसी तरह काम करे क्योंकि यह मानक धाराओं के लिए काम करता है (ताकि आप एसटीएल लाइब्रेरी का पुनः उपयोग कर सकें मानक धाराओं के लिए कार्य)। उपर्युक्त का एकमात्र गैर-अंतर्दृष्टि बिट संशोधित कर रहा है कि स्ट्रीम बफर कैसे काम करता है। –

+0

क्या आप कोई पुस्तक या कुछ संसाधन सुझा सकते हैं, मैं गहराई में मानक टेम्पलेट लाइब्रेरी को समझना चाहता हूं (न केवल इसका उपयोग कर रहा हूं, बल्कि यह वास्तव में कैसे काम करता है) –

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

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