C ++ এ ifstream ব্যবহার করে লাইন দ্বারা ফাইল লাইন পড়ুন


612

File.txt এর বিষয়বস্তু হ'ল:

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

যেখানে 5 3একটি সমন্বিত জুটি। আমি কীভাবে সি ++ এ লাইনে এই ডেটা লাইনটি প্রসেস করব?

আমি প্রথম লাইন পেতে সক্ষম হয়েছি, তবে আমি ফাইলটির পরবর্তী লাইনটি কীভাবে পাব?

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()টোকেন-ভিত্তিক নিষ্কাশন করার পরে ব্যবহার করেন তবে স্পুরিয়াস খালি লাইনগুলি শেষ হতে পারে a ইতিমধ্যে লাইন।


1
@ অ্যাডওয়ার্ডারাক: "টোকেন হিসাবে কমা" অর্থ কী তা আমি বুঝতে পারি না। কমাগুলি পূর্ণসংখ্যার প্রতিনিধিত্ব করে না।
কেরেরেক এসবি

8
ওপি দুটি পূর্ণসংখ্যার সীমাবদ্ধ করতে একটি স্থান ব্যবহার করেছিল। আমি জানতে চেয়েছিলাম যে ওপি যখন কমা একটি ডিলিমিটার হিসাবে ব্যবহার করে, তখন (ইনফিল >> এ >> বি) কাজ করবে কিনা, কারণ এটি আমার নিজের প্রোগ্রামে দৃশ্যমান
এডওয়ার্ড কারাক

30
@ এডওয়ার্ডারাক: আহ, তাই যখন আপনি "টোকেন" বলতেন তখন আপনি "ডিলিমিটার" বোঝাতেন। ঠিক। কমা দিয়ে আপনি বলবেন:int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
কেরেরেক এসবি

11
@ কেরেকএসবি: হু আমি ভৃল ছিলাম. আমি জানি না যে এটি করতে পারে। পুনরায় লেখার জন্য আমার নিজস্ব কিছু কোড থাকতে পারে।
মার্ক এইচ

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;অবশ্য oofstreamজন্য ব্রিদিং output। আপনি যদি ফাইল (ইনপুট) থেকে পড়তে চান তবে ব্যবহার করুন ifstream। আপনি উভয়ই পড়তে এবং লিখতে চাইলে ব্যবহার করুন fstream


8
আপনার সমাধানটি কিছুটা উন্নত হয়েছে: কেরেক এসবি-র দ্বিতীয় সমাধানের বিপরীতে ফাইল রিড-ইন করার পরে আপনার লাইন ভেরিয়েবলটি দৃশ্যমান নয় যা ভাল এবং সাধারণ সমাধানও।
ড্যানিয়েলটুজ

3
getlineহয় string দেখুন , তাই ভুলবেন না#include <string>
mxmlnkn

55

সি ++ এ লাইন দ্বারা একটি ফাইল লাইন পড়া কিছু ভিন্ন উপায়ে করা যেতে পারে।

[দ্রুত] স্ট্যান্ড সহ লুপ: গেটলাইন ()

সবচেয়ে সহজ পন্থাটি হল একটি স্ট্যান্ড :: আইফ্রিমি এবং স্টাডি :: গেটলাইন () কলগুলি ব্যবহার করে লুপ খুলুন। কোডটি পরিষ্কার এবং বুঝতে সহজ।

#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();
}

[দ্রুত] বুস্টের ফাইল_সেসিফিকেশন_সোর্স ব্যবহার করুন

আরেকটি সম্ভাবনা হ'ল বুস্ট লাইব্রেরিটি ব্যবহার করা, তবে কোডটি আরও কিছুটা ভার্বোস পায়। পারফরম্যান্সটি উপরের কোডটির সাথে বেশ মিল (স্টাডি :: গেটলাইন () এর সাথে লুপ)।

#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();
        }
    }
}

[দ্রুততম] সি কোড ব্যবহার করুন

যদি আপনার সফ্টওয়্যারটির জন্য পারফরম্যান্স সমালোচনা হয় তবে আপনি সি ভাষা ব্যবহারের বিষয়টি বিবেচনা করতে পারেন। এই কোডটি উপরের সি ++ সংস্করণগুলির চেয়ে 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 ফাইলগুলির সাথে কোডটি পরীক্ষা করেছি যাতে ১০,০০,০০০ লাইন, ১,০০,০০০ লাইন এবং ১০,০০,০০০ পাঠ্য পাঠ্য রয়েছে। পাঠ্যের প্রতিটি লাইনে 10 টি করে শব্দ থাকে। প্রোগ্রামটি -O3অপ্টিমাইজেশনের সাথে সংকলিত /dev/nullহয়েছে এবং পরিমাপ থেকে লগিং সময়ের পরিবর্তনশীল অপসারণের জন্য এর আউটপুটকে ফরোয়ার্ড করা হয়। সর্বশেষে, তবে অন্তত নয়, কোডের প্রতিটি টুকরো printf()ধারাবাহিকতার জন্য প্রতিটি লাইনে লগ করে ।

ফলাফলগুলি কোডের প্রতিটি টুকরো ফাইলগুলি পড়তে যে সময়টি (এমএসে) দেখায়।

দুটি সি ++ পদ্ধতির মধ্যে পারফরম্যান্সের পার্থক্যটি ন্যূনতম এবং অনুশীলনে কোনও পার্থক্য করা উচিত নয়। সি কোডটির পারফরম্যান্সই বেনমার্কটিকে চিত্তাকর্ষক করে তোলে এবং গতির দিক থেকে গেম চেঞ্জার হতে পারে।

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

এখানে চিত্র বর্ণনা লিখুন


1
আপনি কনসোল আউটপুটগুলিতে সি এর সাথে সি ++ এর সিঙ্ক্রোনাইজেশন মুছে ফেললে কী হবে? আপনি std::coutবনাম এর ডিফল্ট আচরণের একটি পরিচিত অসুবিধা পরিমাপ করছেন printf
ব্যবহারকারী 4581301

2
এই উদ্বেগ আনার জন্য ধন্যবাদ। আমি পরীক্ষাগুলি আবার করেছি এবং পারফরম্যান্স এখনও একইরকম। printf()ধারাবাহিকতার জন্য সমস্ত ক্ষেত্রে ফাংশনটি ব্যবহার করার জন্য আমি কোডটি সম্পাদনা করেছি । আমি std::coutসব ক্ষেত্রে ব্যবহার করার চেষ্টা করেছি এবং এটি একেবারেই কোনও পার্থক্য তৈরি করে নি। আমি যেমন পাঠ্যটিতে বর্ণনা করেছি, প্রোগ্রামটির আউটপুট চলে যায় /dev/nullতাই লাইনগুলি মুদ্রণের সময় পরিমাপ করা হয় না।
হুগোটিক্সির

6
খাঁজকাটা। ধন্যবাদ। মন্দা যেখানে আশ্চর্য।
ব্যবহারকারী 4581301

4
হাই @ হুগো টিক্সির আমি জানি এটি একটি পুরানো থ্রেড, আমি আপনার ফলাফলগুলি প্রতিলিপি দেওয়ার চেষ্টা করেছি এবং সি এবং সি ++ github.com/simonsso/readfile_benchmark এর
সিমসন

ডিফল্টরূপে, সি ++ ইন-আউট স্ট্রিমগুলি সিঙ্ক্রোনাইজ হয় 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;কারণ অন্যথায় আপনি ধরে নিচ্ছেন যে আপনার ইনপুট স্ট্রিমটি হোয়াইটস্পেস-এড়িয়ে যাওয়া মোডে রয়েছে।
ডার্কো ভ্যাবারিক

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

যদিও ম্যানুয়ালি ফাইলটি বন্ধ করার দরকার নেই তবে ফাইলের ভেরিয়েবলের পরিধি আরও বড় হলে এটি করা ভাল idea

    ifstream infile(szFilePath);

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

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

নিশ্চিত নয় যে এটি একটি নিচে ভোটের যোগ্য served ওপি প্রতিটি লাইন পাওয়ার উপায় চেয়েছিল। এই উত্তরটি তা করে এবং ফাইলটি বন্ধ হয়ে যায় তা নিশ্চিত করার দুর্দান্ত পরামর্শ দেয়। একটি সাধারণ প্রোগ্রামের জন্য এটির প্রয়োজন নাও হতে পারে তবে ন্যূনতম একটি দুর্দান্ত অভ্যাস গঠনের প্রয়োজন। এটি পৃথক পৃথক রেখাগুলি প্রক্রিয়া করতে কোডের কয়েকটি লাইন যুক্ত করে উন্নত হতে পারে তবে সামগ্রিকভাবে ওপিএস প্রশ্নের সহজ উত্তর answer
Xandor

2

এই উত্তরটি ভিজ্যুয়াল স্টুডিও 2017 এর জন্য এবং আপনি যদি পাঠ্য ফাইল থেকে পড়তে চান তবে কোন স্থানটি আপনার সংকলিত কনসোল অ্যাপ্লিকেশনের সাথে সম্পর্কিত।

প্রথমে আপনার সমাধান ফোল্ডারে আপনার পাঠ্য ফাইল (এই ক্ষেত্রে test.txt) রাখুন। সংকলনের পরে টেক্সট ফাইলটি একই ফোল্ডারে অ্যাপ্লিকেশননেম.এক্সই দিয়ে রাখুন

সি: \ ব্যবহারকারী \ "USERNAME" \ উৎস \ Repos \ "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

এটি সি ++ প্রোগ্রামে ডেটা লোড করার একটি সাধারণ সমাধান এবং রিডলাইন ফাংশনটি ব্যবহার করে। এটি সিএসভি ফাইলগুলির জন্য পরিবর্তিত হতে পারে তবে ডিলিমিটারটি এখানে একটি স্থান space

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
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.