2009-08-24 9 views
18

मैं जो इस तरह दिखेगा डेटा फ़ाइलों में पढ़ने की जरूरत है:कैसे एक ASCII फ़ाइल (C++) से संख्या को पढ़ने के लिए

* SZA: 10.00 
2.648 2.648 2.648 2.648 2.648 2.648 2.648 2.649 2.650 2.650 
2.652 2.653 2.652 2.653 2.654 2.654 2.654 2.654 2.654 2.654 
2.654 2.654 2.654 2.655 2.656 2.656 2.657 2.657 2.657 2.656 
2.656 2.655 2.655 2.653 2.653 2.653 2.654 2.658 2.669 2.669 
2.667 2.666 2.666 2.664 2.663 2.663 2.663 2.662 2.663 2.663 
2.663 2.663 2.663 2.663 2.662 2.660 2.656 2.657 2.657 2.657 
2.654 2.653 2.652 2.651 2.648 2.647 2.646 2.642 2.641 2.637 
2.636 2.636 2.634 2.635 2.635 2.635 2.635 2.634 2.633 2.633 
2.633 2.634 2.634 2.635 2.637 2.638 2.637 2.639 2.640 2.640 
2.639 2.640 2.640 2.639 2.639 2.638 2.640 2.640 2.638 2.639 
2.638 2.638 2.638 2.638 2.637 2.637 2.637 2.634 2.635 2.636 
2.637 2.639 2.641 2.641 2.643 2.643 2.643 2.642 2.643 2.642 
2.641 2.642 2.642 2.643 2.645 2.645 2.645 2.645 

क्या तैरता की एक सरणी में इस फ़ाइल को पढ़ने के लिए सबसे खूबसूरत तरीका क्या होगा?

मुझे पता है कि प्रत्येक पंक्ति को स्ट्रिंग में कैसे पढ़ा जाए, और मुझे पता है कि atof() का उपयोग करके स्ट्रिंग को फ़्लोट में कैसे परिवर्तित किया जाए। लेकिन मैं बाकी को सबसे आसान कैसे कर सकता हूं?

मैंने स्ट्रिंग बफर के बारे में सुना है, क्या इससे मेरी मदद हो सकती है?

उत्तर

11

चूंकि इसे सी ++ के रूप में टैग किया गया है, इसलिए सबसे स्पष्ट तरीका धाराओं का उपयोग करेगा। मेरे सिर के ऊपर से, कुछ इस तरह कर सकते हैं:

std::vector<float> readFile(std::istream& is) 
{ 
    char chdummy; 
    is >> std::ws >> chdummy >> std::ws; 
    if(!is || chdummy != '*') error(); 
    std::string strdummy; 
    std::getline(is,strdummy,':'); 
    if(!is || strdummy != "SZA") error(); 

    std::vector<float> result; 
    for(;;) 
    { 
    float number; 
    if(!is>>number) break; 
    result.push_back(number); 
    } 
    if(!is.eof()) error(); 

    return result; 
} 

क्यों float, BTW? आमतौर पर, double बहुत बेहतर है।

संपादित, क्योंकि यह सवाल उठाया गया था कि क्या vector की एक प्रति लौटने एक अच्छा विचार है:

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

(यह भी ध्यान दें कि रावलू समर्थन के साथ सी ++ 1 एक्स, उम्मीद है कि जल्द ही आपके पास एक कंपाइलर के माध्यम से उपलब्ध होगा, इस चर्चा को प्रस्तुत करेगा, क्योंकि यह कार्य से लौटने पर वेक्टर को कॉपी करने से रोक देगा।)

+0

जेनेरिक "सभी फ्लोट पढ़ें" -लूप 'फ्लोट नंबर होगा; जबकि (है >> संख्या) परिणाम.push_back (संख्या); ' – sth

+0

हालांकि आपका निश्चित रूप से बराबर है। – sth

+0

@sth: वास्तव में, यह अधिक terse है, हालांकि मुझे लूप से 'संख्या' चर "लीकिंग" पसंद नहीं है। – sbi

2

मैं कुछ इस तरह करना होगा:

std::ifstream input("input.txt"); 
std::vector<float> floats; 
std::string header; 
std::getline(input, header); // read in the "* SZA: 10.00" line 
if(header_is_correct(header)) { 
    float value; 
    // while we could successfully read in a float from the file... 
    while(input >> value) { 
     // store it in the vector. 
     floats.push_back(value); 
    } 
} 

नोट:header_is_correct(header) सिर्फ एक उदाहरण है, तो आप मैन्युअल वहाँ कि पहली पंक्ति के लिए जाँच किसी भी त्रुटि को लागू करने की आवश्यकता होगी।

#include <iostream> 
#include <string> 
#include <deque> 
#include <iterator> 

#include "strtk.hpp" 

int main() 
{ 
    std::deque<float> flist; 
    strtk::for_each_line("file.txt", 
         [&flist](const std::string& line) 
         { strtk::parse(line," ",flist); } 
         ); 
    std::copy(flist.begin(),flist.end(), 
       std::ostream_iterator<float>(std::cout,"\t")); 
    return 0; 
} 

अधिक उदाहरण C++ String Toolkit (StrTk) Tokenizer में पाया जा सकता:

+0

डाउनवोट क्यों? मैंने इसका परीक्षण किया है और यह फ़ाइल से प्रत्येक फ्लोट को वेक्टर में सही ढंग से पढ़ता है। –

18

String Toolkit Library (Strtk) आपकी समस्या के लिए निम्न समाधान है।

+0

दिलचस्प, हालांकि आपको स्पष्ट होना चाहिए कि यह केवल सी ++ 0x कंपाइलर्स के लिए है। –

+18

बहुत सच है लेकिन लैम्ब्डा को आसानी से संरचना शैली की भविष्यवाणी में रखा जा सकता है। मैंने शैली और भविष्य के संदर्भों के लिए सोचा (अब इसे 1-2 साल का सामना करना पड़ता है, उपर्युक्त कोड और समान रूप से मानक होगा) कि यह एक अच्छा विचार होगा कि चीजों को कैसे किया जा सकता है। –

+12

मुझे यह पसंद आया। नए भेड़ के बच्चे का अच्छा उपयोग, भले ही यह जवाब न हो। –

2

सरल समाधान एसटीएल का उपयोग कर एल्गोरिदम:

#include <vector> 
#include <iostream> 
#include <string> 
#include <iterator> 

struct data 
{ 
    float first; // in case it is required, and assuming it is 
       // different from the rest 
    std::vector<float> values; 
}; 

data read_file(std::istream& in) 
{ 
    std::string tmp; 
    data d; 
    in >> tmp >> tmp >> d.first; 
    if (!in) throw std::runtime_error("Failed to parse line"); 

    std::copy(std::istream_iterator<float>(in), std::istream_iterator<float>(), 
     std::back_inserter<float>(d.values)); 

    return data; 
} 

तुम सच में एक सरणी का उपयोग करने की आवश्यकता है, तो आपको पहले यह (या तो गतिशील रूप से या स्थिर आप आकार पता है) का आवंटन होगा और फिर आप एक ही प्रतिलिपि का उपयोग कर सकते एल्गोरिथ्म

// parsing the first line would be equivalent 
float data[128]; // assuming 128 elements known at compile time 
std::copy(std::istream_iterator<float>(is), std::istream_iterator<float>(), 
     data); 

लेकिन मैं, यहां तक ​​कि इस मामले में std :: वेक्टर उपयोग करने की अनुशंसा करता है, तो आप आप हमेशा पहले तत्व के सूचक के रूप में यह पारित कर सकते हैं एक समारोह है कि एक सरणी लेता है में डेटा पारित करने के लिए की आवश्यकता होगी:

void f(float* data, int size); 
int main() 
{ 
    std::vector<float> v; // and populate 
    f(&v[0], v.size()); // memory is guaranteed to be contiguous 
} 
संबंधित मुद्दे