C ++ में ifstream का उपयोग करके लाइन द्वारा फ़ाइल लाइन पढ़ें


612

File.txt की सामग्री हैं:

5 3
6 4
7 1
10 5
11 6
12 3
12 4

5 3एक समन्वय जोड़ी कहां है। मैं इस डेटा लाइन को C ++ में लाइन द्वारा कैसे संसाधित करूं?

मैं पहली पंक्ति प्राप्त करने में सक्षम हूं, लेकिन मैं फ़ाइल की अगली पंक्ति कैसे प्राप्त करूं?

ifstream myfile;
myfile.open ("text.txt");

जवाबों:


916

सबसे पहले ifstream:

#include <fstream>
std::ifstream infile("thefile.txt");

दो मानक विधियाँ हैं:

  1. मान लें कि हर पंक्ति में दो नंबर होते हैं और टोकन द्वारा टोकन पढ़ा जाता है:

    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
    
  2. लाइन-आधारित पार्सिंग, स्ट्रिंग धाराओं का उपयोग करते हुए:

    #include <sstream>
    #include <string>
    
    std::string line;
    while (std::getline(infile, line))
    {
        std::istringstream iss(line);
        int a, b;
        if (!(iss >> a >> b)) { break; } // error
    
        // process pair (a,b)
    }
    

आपको (1) और (2) का मिश्रण नहीं करना चाहिए, क्योंकि टोकन-आधारित पार्सिंग नईलाइन्स को शोभा नहीं देता है, इसलिए यदि आप getline()टोकन-आधारित निष्कर्षण के बाद आप का उपयोग करते हैं, तो आप खाली खाली लाइनों के साथ समाप्त हो सकते हैं। पहले से ही लाइन।


1
@EdwardKarak: मुझे समझ में नहीं आता कि "टोकन के रूप में कॉमा" का क्या अर्थ है। Commas पूर्णांक का प्रतिनिधित्व नहीं करते हैं।
केरेक एसबी

8
ओपी ने दो पूर्णांकों को परिसीमित करने के लिए एक स्थान का उपयोग किया। मैं जानना चाहता था कि जब (शिशु >> ए >> बी) काम करेगा अगर ओपी एक अल्पविराम के रूप में एक सीमांकक का उपयोग करता है, क्योंकि मेरे स्वयं के कार्यक्रम में यही परिदृश्य है
एडवर्ड करक

30
@EdwardKarak: आह, इसलिए जब आपने "टोकन" कहा था तो आपका मतलब "सीमांत" था। सही। अल्पविराम के साथ, आप कहेंगे:int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
केरेक एसबी

11
@KerrekSB: हुह। मैं गलत था। मुझे नहीं पता था कि वह ऐसा कर सकती है। मेरे पास फिर से लिखने के लिए अपना खुद का कुछ कोड हो सकता है।
मार्क एच

4
while(getline(f, line)) { }निर्माण की एक व्याख्या के लिए और त्रुटि से निपटने के संबंध में कृपया इस (मेरे) लेख पर एक नज़र डालें: gehrcke.de/2011/06/… (मुझे लगता है कि मुझे यहाँ बुरा विवेक पोस्ट करने की आवश्यकता नहीं है, यह थोड़ा पूर्व भी है- यह उत्तर)।
डॉ। जन-फिलिप गेर्के

175

ifstreamफ़ाइल से डेटा पढ़ने के लिए उपयोग करें :

std::ifstream input( "filename.ext" );

यदि आपको वास्तव में लाइन द्वारा लाइन पढ़ने की आवश्यकता है, तो यह करें:

for( std::string line; getline( input, line ); )
{
    ...for each line in input...
}

लेकिन आपको शायद समन्वित जोड़े निकालने की जरूरत है:

int x, y;
input >> x >> y;

अपडेट करें:

अपने कोड में आप का उपयोग ofstream myfile;, तथापि oमें ofstreamके लिए खड़ा है output। यदि आप फ़ाइल (इनपुट) के उपयोग से पढ़ना चाहते हैं ifstream। यदि आप पढ़ना और लिखना दोनों उपयोग करना चाहते हैं fstream


8
आपका समाधान थोड़ा सुधार हुआ है: आपके लाइन वेरिएबल केरेक एसबी के दूसरे समाधान के विपरीत फाइल रीड-इन के बाद दिखाई नहीं देता है जो कि अच्छा और सरल समाधान भी है।
डैनियलट्यूज

3
getlineमें string देखें , तो मत भूलना#include <string>
mxmlnkn

55

C ++ में लाइन द्वारा एक फ़ाइल लाइन पढ़ना कुछ अलग तरीकों से किया जा सकता है।

[तेज] std के साथ पाश :: getline ()

सबसे सरल तरीका एक std :: ifstream और पाश का उपयोग std :: getline () कॉल को खोलना है। कोड साफ और समझने में आसान है।

#include <fstream>

std::ifstream file(FILENAME);
if (file.is_open()) {
    std::string line;
    while (std::getline(file, line)) {
        // using printf() in all tests for consistency
        printf("%s", line.c_str());
    }
    file.close();
}

[फास्ट] बूस्ट के file_description_source का उपयोग करें

एक और संभावना बूस्ट पुस्तकालय का उपयोग करने के लिए है, लेकिन कोड थोड़ा और अधिक क्रिया हो जाता है। प्रदर्शन ऊपर के कोड के समान है (std के साथ लूप :: getline ())।

#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <fcntl.h>

namespace io = boost::iostreams;

void readLineByLineBoost() {
    int fdr = open(FILENAME, O_RDONLY);
    if (fdr >= 0) {
        io::file_descriptor_source fdDevice(fdr, io::file_descriptor_flags::close_handle);
        io::stream <io::file_descriptor_source> in(fdDevice);
        if (fdDevice.is_open()) {
            std::string line;
            while (std::getline(in, line)) {
                // using printf() in all tests for consistency
                printf("%s", line.c_str());
            }
            fdDevice.close();
        }
    }
}

[सबसे तेज] C कोड का उपयोग करें

यदि प्रदर्शन आपके सॉफ़्टवेयर के लिए महत्वपूर्ण है, तो आप C भाषा का उपयोग करने पर विचार कर सकते हैं। यह कोड ऊपर C ++ संस्करणों की तुलना में 4-5 गुना तेज हो सकता है, नीचे बेंचमार्क देखें

FILE* fp = fopen(FILENAME, "r");
if (fp == NULL)
    exit(EXIT_FAILURE);

char* line = NULL;
size_t len = 0;
while ((getline(&line, &len, fp)) != -1) {
    // using printf() in all tests for consistency
    printf("%s", line);
}
fclose(fp);
if (line)
    free(line);

बेंचमार्क - कौन सा तेज है?

मैंने ऊपर दिए गए कोड के साथ कुछ प्रदर्शन बेंचमार्क किए हैं और परिणाम दिलचस्प हैं। मैंने ASCII फ़ाइलों के साथ कोड का परीक्षण किया है जिसमें 100,000 पंक्तियाँ, 1,000,000 पंक्तियाँ और पाठ की 10,000,000 पंक्तियाँ हैं। पाठ की प्रत्येक पंक्ति में औसतन 10 शब्द हैं। कार्यक्रम को -O3अनुकूलन के साथ संकलित किया गया है और /dev/nullमाप से लॉगिंग समय चर को हटाने के लिए इसके आउटपुट को अग्रेषित किया गया है। अंतिम, लेकिन कम से कम, कोड का प्रत्येक टुकड़ा printf()स्थिरता के लिए फ़ंक्शन के साथ प्रत्येक पंक्ति को लॉग नहीं करता है ।

परिणाम समय (एमएस में) दिखाते हैं कि कोड का प्रत्येक टुकड़ा फाइलों को पढ़ने के लिए लिया गया था।

दो C ++ दृष्टिकोणों के बीच प्रदर्शन अंतर न्यूनतम है और अभ्यास में कोई अंतर नहीं होना चाहिए। C कोड का प्रदर्शन बेंचमार्क को प्रभावशाली बनाता है और गति के मामले में गेम चेंजर हो सकता है।

                             10K lines     100K lines     1000K lines
Loop with std::getline()         105ms          894ms          9773ms
Boost code                       106ms          968ms          9561ms
C code                            23ms          243ms          2397ms

यहाँ छवि विवरण दर्ज करें


1
यदि आप कंसोल आउटपुट पर C ++ के C के साथ सिंक्रोनाइज़ेशन हटा देते हैं तो क्या होगा? आप std::coutबनाम के डिफ़ॉल्ट व्यवहार के ज्ञात नुकसान को माप सकते हैं printf
user4581301

2
इस चिंता को लाने के लिए धन्यवाद। मैंने परीक्षण फिर से कर लिए हैं और प्रदर्शन अभी भी वही है। मैंने printf()निरंतरता के लिए सभी मामलों में फ़ंक्शन का उपयोग करने के लिए कोड को संपादित किया है । मैंने भी std::coutसभी मामलों में उपयोग करने की कोशिश की है और इससे कोई फर्क नहीं पड़ा। जैसा कि मैंने अभी पाठ में वर्णन किया है, प्रोग्राम का आउटपुट /dev/nullलाइनों को प्रिंट करने के लिए समय पर मापा जाता है।
ह्यूगोटेइसीरा जूल

6
ग्रूवी। धन्यवाद। आश्चर्य है कि मंदी कहाँ है।
user4581301

4
हाय @HugoTeixeira मुझे पता है कि यह एक पुराना धागा है, मैंने आपके परिणामों को दोहराने की कोशिश की और c और c ++ के बीच कोई महत्वपूर्ण अंतर नहीं देख सका। github.com/simonsso/readfile_benchmark
Simson

डिफ़ॉल्ट रूप से, C ++ इन-आउट स्ट्रीम के साथ सिंक्रनाइज़ किया जाता है cstdio। आपको सेटिंग के साथ प्रयास करना चाहिए था std::ios_base::sync_with_stdio(false)। मुझे लगता है कि आपने बहुत बेहतर प्रदर्शन प्राप्त किया होगा (यह गारंटी नहीं है कि जब से इसे लागू किया गया है, जब सिंक्रनाइज़ेशन बंद हो जाता है)।
फेरेनोर

11

चूंकि आपके निर्देशांक जोड़े के रूप में एक साथ हैं, तो उनके लिए एक संरचना क्यों नहीं लिखनी चाहिए?

struct CoordinatePair
{
    int x;
    int y;
};

तो आप istreams के लिए एक अतिभारित निष्कर्षण ऑपरेटर लिख सकते हैं:

std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
    is >> coordinates.x >> coordinates.y;

    return is;
}

और फिर आप इस तरह एक वेक्टर में सीधे निर्देशांक की एक फ़ाइल पढ़ सकते हैं:

#include <fstream>
#include <iterator>
#include <vector>

int main()
{
    char filename[] = "coordinates.txt";
    std::vector<CoordinatePair> v;
    std::ifstream ifs(filename);
    if (ifs) {
        std::copy(std::istream_iterator<CoordinatePair>(ifs), 
                std::istream_iterator<CoordinatePair>(),
                std::back_inserter(v));
    }
    else {
        std::cerr << "Couldn't open " << filename << " for reading\n";
    }
    // Now you can work with the contents of v
}

1
क्या होता है जब intधारा में से दो टोकन पढ़ना संभव नहीं होता है operator>>? कोई इसे एक पीछे वाले पार्सर के साथ कैसे काम कर सकता है (यानी जब operator>>असफल हो जाता है, तो स्ट्रीम को पिछली स्थिति में वापस लौटाएं वापस झूठे या कुछ और जैसे)?
fferri

यदि दो intटोकन पढ़ना संभव नहीं है , तो isधारा का मूल्यांकन होगा falseऔर रीडिंग लूप उस बिंदु पर समाप्त हो जाएगा। आप operator>>व्यक्तिगत रीड्स के रिटर्न वैल्यू की जांच करके इसका पता लगा सकते हैं । यदि आप स्ट्रीम वापस करना चाहते हैं, तो आप कॉल करेंगे is.clear()
मार्टिन ब्रॉडहर्स्ट

में operator>>इसे और अधिक कहने के लिए सही है is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws;अन्यथा जब से तुम मानते हैं कि अपने इनपुट धारा खाली स्थान के-लंघन मोड में है।
Darko Veberic

7

यदि इनपुट है, तो स्वीकृत उत्तर पर विस्तार करना:

1,NYC
2,ABQ
...

आप अभी भी इस तरह से एक ही तर्क को लागू कर पाएंगे:

#include <fstream>

std::ifstream infile("thefile.txt");
if (infile.is_open()) {
    int number;
    std::string str;
    char c;
    while (infile >> number >> c >> str && c == ',')
        std::cout << number << " " << str << "\n";
}
infile.close();

2

हालाँकि, फ़ाइल को मैन्युअल रूप से बंद करने की कोई आवश्यकता नहीं है, लेकिन ऐसा करने के लिए फ़ाइल चर का दायरा बड़ा होने पर ऐसा करना अच्छा है:

    ifstream infile(szFilePath);

    for (string line = ""; getline(infile, line); )
    {
        //do something with the line
    }

    if(infile.is_open())
        infile.close();

यकीन नहीं कि यह एक डाउन वोट का हकदार था। ओपी ने प्रत्येक पंक्ति को प्राप्त करने का तरीका पूछा। यह उत्तर ऐसा करता है और यह सुनिश्चित करता है कि फ़ाइल बंद होने का एक बड़ा सिरा मिलता है। एक साधारण कार्यक्रम के लिए इसकी आवश्यकता नहीं हो सकती है, लेकिन इसे बनाने के लिए कम से कम एक महान आदत है। कोड को कुछ पंक्तियों में जोड़कर इसे खींचा जा सकता है, लेकिन इसे ओपीडी प्रश्न का सबसे सरल उत्तर है।
Xandor

2

यह उत्तर दृश्य स्टूडियो 2017 के लिए है और यदि आप पाठ फ़ाइल से पढ़ना चाहते हैं, तो कौन सा स्थान आपके संकलित कंसोल एप्लिकेशन के सापेक्ष है।

सबसे पहले अपने टेक्स्ट फ़ोल्डर (इस मामले में test.txt) को अपने समाधान फ़ोल्डर में डालें। कंपाइल करने के बाद ApplicationName.exe के साथ टेक्स्ट फाइल को उसी फोल्डर में रखें

C: \ Users \ "उपयोगकर्ता नाम" \ स्रोत \ रेपोस \ "solutionName" \ "solutionName"

#include <iostream>
#include <fstream>

using namespace std;
int main()
{
    ifstream inFile;
    // open the file stream
    inFile.open(".\\test.txt");
    // check if opening a file failed
    if (inFile.fail()) {
        cerr << "Error opeing a file" << endl;
        inFile.close();
        exit(1);
    }
    string line;
    while (getline(inFile, line))
    {
        cout << line << endl;
    }
    // close the file stream
    inFile.close();
}

1

यह C ++ प्रोग्राम में डेटा लोड करने का एक सामान्य समाधान है, और रीडलाइन फ़ंक्शन का उपयोग करता है। इसे CSV फ़ाइलों के लिए संशोधित किया जा सकता है, लेकिन सीमांकक यहां एक स्थान है।

int n = 5, p = 2;

int X[n][p];

ifstream myfile;

myfile.open("data.txt");

string line;
string temp = "";
int a = 0; // row index 

while (getline(myfile, line)) { //while there is a line
     int b = 0; // column index
     for (int i = 0; i < line.size(); i++) { // for each character in rowstring
          if (!isblank(line[i])) { // if it is not blank, do this
              string d(1, line[i]); // convert character to string
              temp.append(d); // append the two strings
        } else {
              X[a][b] = stod(temp);  // convert string to double
              temp = ""; // reset the capture
              b++; // increment b cause we have a new number
        }
    }

  X[a][b] = stod(temp);
  temp = "";
  a++; // onto next row
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.