-2

I'm new to file read/write in c++. Please someone help me the best way to read the file somewhat like shown below ta class like this

class Student
{
public:
string fName;
string sName;
int mark

};
// file.txt each data is ends with newline and metadata ends with ';'
Firstname1;SecondName1;Mark1 
Firstname2;SecondName2;Mark2
Firstname3;SecondName3;Mark3
Firstname4;SecondName4;Mark4
Firstname5;SecondName5;Mark5

please someone help me to find a best way

phuclv
  • 37,963
  • 15
  • 156
  • 475
Casper
  • 9
  • 1
    Refer to [how to ask](https://stackoverflow.com/help/how-to-ask) where the first step is to *"search and then research"* and you'll find plenty of related SO posts for this. – Jason Sep 17 '22 at 04:17
  • 2
    This is also explained in any beginner [c++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – Jason Sep 17 '22 at 04:17
  • 1
    [How can I read and parse CSV files in C++?](https://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c) and use semicolon instead of comma as the delimiter. – Retired Ninja Sep 17 '22 at 04:23
  • Start by reading the docs, try something on your own before asking for help. – Florin C. Sep 17 '22 at 09:55

1 Answers1

0

So, we have here 2 problems to solve.

  1. read data from a file
  2. split the read data into its parts

The format of the source text file is so called "CSV", for "Comma Separated Values". Instead of comma, any other meaningfull separator may be used.

So, what needs to be done?

  • Open the file and check, if it could be opened
  • In a loop read line by line from the file
  • split the values into its parts
  • store the parts in your struct

The challenge for you is here the "splitting" of the string. There are many many many potential solutions, let me share one often used approach with std::getline.

std::getline basically reads characters from an input stream and places them into a string. Reading is done until a delimiter is found. If you do not specifically provide a delimiter as input parameter, then '\n' is assumed. So, it will read a complete line from a stream (file).

Then, because many people do not understand the pitfalls in using a mix of formatted and unformatted input, the read line is put into a std::istringstream. This is also more robust/resilient against problems Then we can extract the parts of the string again with using std::getline.

One potential example could be:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

class Student
{
public:
    std::string fName{};
    std::string sName{};
    int mark{};
};

int main() {

    // Open file and check, if it could be opened
    if (std::ifstream sourceFileStream{ "file.txt" }; sourceFileStream) {

        // The file could be opened. Define a vector, where we store all Student data
        std::vector<Student> students{};

        // Read all lines of the file
        for (std::string line; std::getline(sourceFileStream, line); ) {

            // Put the line into an std::istringstream, to extract the parts
            std::istringstream iss{ line };

            // Define a temporary Student for storing the parts
            Student tempStudent{};

            // Get the parts
            std::getline(iss, tempStudent.fName, ';');
            std::getline(iss, tempStudent.sName, ';');
            // Use formatted input function to get the mark and convert it to an int
            iss >> tempStudent.mark;

            // So, now all parts are in the tempStudent. Add this to the result
            students.push_back(tempStudent);
        }

        // For debug purposes, we show all read data
        for (const Student& student : students)
            std::cout << student.fName << '\t' << student.sName << "\t Mark: " << student.mark << '\n';
    }
    else
        // File could not be opened. Show error message
        std::cerr << "\n\nError: 'file.txt' could not be opened\n";
}

For the more experienced users. In C++ we often use a more object oriented approach. We store the data and the methods, operating on that data in the class.

C++ allows us to override the extraction >> and inserter << operator. Those will then be part of the class and make IO easier.

Please see the little bit more advanced solution below:

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

class Student
{
public:
    std::string fName{};
    std::string sName{};
    int mark{};

    friend std::istream& operator >> (std::istream& is, Student& s) {
        if (std::string line{}; std::getline(is, line)) {
            std::istringstream iss{ line };
            std::getline(std::getline(iss, s.fName, ';'), s.sName) >> s.mark;
        }
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const Student& s) {
        return os << s.fName << '\t' << s.sName << "\t Mark: " << s.mark;
    }
};
class Students
{
public:
    std::vector<Student> data{};
    friend std::istream& operator >> (std::istream& is, Students& s) {
        s.data = { std::istream_iterator<Student>(is),{} };
        return is;
    }
    friend std::ostream& operator << (std::ostream& os, const Students& s) {
        for (const Student& d : s.data) os << d << '\n';
        return os;
    }
};

int main() {

    // Open file and check, if it could be opened
    if (std::ifstream sourceFileStream{ "file.txt" }; sourceFileStream) {

        // The file could be opened. Define a instance of Students
        Students students{};

        // Read all students
        sourceFileStream >> students;

        // Show all data
        std::cout << students;
    }
    else
        // File could not be opened. SHow error message
        std::cerr << "\n\nError: 'file.txt' could not be opened\n";
}

A M
  • 14,694
  • 5
  • 19
  • 44