jeanc
jeanc

Reputation: 4843

What's the correct way to read a text file in C++?

I need to make a program in C++ that must read and write text files line by line with an specific format, but the problem is that in my PC I work in Windows, and in College they have Linux and I am having problems because of line endings are different in these OS.

I am new to C++ and don't know could I make my program able read the files no matter if they were written in Linux or Windows. Can anybody give me some hints? thanks!

The input is like this:

James White 34 45.5 10 black
Miguel Chavez 29 48.7 9 red
David McGuire 31 45.8 10 blue

Each line being a record of a struct of 6 variables.

Upvotes: 0

Views: 2920

Answers (6)

Domderon
Domderon

Reputation: 383

Here's a simple way to strip string of an extra "\r":

std::ifstream in("TheFile.txt");
std::string line;

std::getline(input, line));
if (line[line.size() - 1] == '\r')
    line.resize(line.size() - 1);

Upvotes: 1

Branko Dimitrijevic
Branko Dimitrijevic

Reputation: 52157

Using the std::getline overload without the last (i.e. delimiter) parameter should take care of the end-of-line conversions automatically:

std::ifstream in("TheFile.txt");
std::string line;

while (std::getline(in, line)) {
    // Do something with 'line'.
}

Upvotes: 1

Harry
Harry

Reputation: 3842

Hi I will give you the answer in stages. Please go trough in order to understand the code.

Stage 1: Design our program: Our program based on the requirements should...:

  • ...include a definition of a data type that would hold the data. i.e. our structure of 6 variables.
  • ...provide user interaction i.e. the user should be able to provide the program, the file name and its location.
  • ...be able to open the chosen file.
  • ...be able to read the file data and write/save them into our structure.
  • ...be able to close the file after the data is read.
  • ...be able to print out of the saved data.

Usually you should split your code into functions representing the above.

Stage 2: Create an array of the chosen structure to hold the data

...
#define MAX 10
...
strPersonData sTextData[MAX];
...

Stage 3: Enable user to give in both the file location and its name:

.......
string sFileName;
cout << "Enter a file name: ";
getline(cin,sFileName);
ifstream inFile(sFileName.c_str(),ios::in);
.....

->Note 1 for stage 3. The accepted format provided then by the user should be:

c:\\SomeFolder\\someTextFile.txt

We use two \ backslashes instead of one \, because we wish it to be treated as literal backslash.

->Note 2 for stage 3. We use ifstream i.e. input file stream because we want to read data from file. This is expecting the file name as c-type string instead of a c++ string. For this reason we use:

..sFileName.c_str()..

Stage 4: Read all data of the chosen file:

...
    while (!inFile.eof())   { //we loop while there is still data in the file to read
...
    }
...

So finally the code is as follows:

#include <iostream>
#include <fstream>
#include <cstring>

#define MAX 10

using namespace std;

int main()
{
    string sFileName;

    struct strPersonData    {
        char c1stName[25];
        char c2ndName[30];
        int iAge;
        double dSomeData1;      //i had no idea what the next 2 numbers represent in your code :D
        int iSomeDate2;
        char cColor[20];        //i dont remember the lenghts of the different colors.. :D
        };

    strPersonData sTextData[MAX];

    cout << "Enter a file name: ";
    getline(cin,sFileName);
    ifstream inFile(sFileName.c_str(),ios::in);

    int i=0;
    while (!inFile.eof())   { //loop while there is still data in the file

       inFile >>sTextData[i].c1stName>>sTextData[i].c2ndName>>sTextData[i].iAge
            >>sTextData[i].dSomeData1>>sTextData[i].iSomeDate2>>sTextData[i].cColor;

        ++i;
    }
    inFile.close();

    cout << "Reading the file finished. See it yourself: \n"<< endl;
    for (int j=0;j<i;j++) {
        cout<<sTextData[j].c1stName<<"\t"<<sTextData[j].c2ndName
            <<"\t"<<sTextData[j].iAge<<"\t"<<sTextData[j].dSomeData1
            <<"\t"<<sTextData[j].iSomeDate2<<"\t"<<sTextData[j].cColor<<endl;
    }
    return 0;
}

I am going to give you some exercises now :D :D

1) In the last loop:

for (int j=0;j<i;j++) {
    cout<<sTextData[j].c1stName<<"\t"<<sTextData[j].c2ndName
        <<"\t"<<sTextData[j].iAge<<"\t"<<sTextData[j].dSomeData1
        <<"\t"<<sTextData[j].iSomeDate2<<"\t"<<sTextData[j].cColor<<endl;}

Why do I use variable i instead of lets say MAX???

2) Could u change the program based on stage 1 on sth like:

int main(){

function1()
function2()
...
functionX()

...return 0;
}

I hope i helped...

Upvotes: 0

shekhar
shekhar

Reputation: 1432

If you know the number of values you are going to read for each record you could simply use the ">>" method. For example:

fstream f("input.txt" std::ios::in);
string tempStr;
double tempVal;

for (number of records) {
    // read the first name
    f >> tempStr;
    // read the last name
    f >> tempStr;
    // read the number
    f >> tempVal;
    // and so on.
}

Shouldn't that suffice ?

Upvotes: 0

annonymously
annonymously

Reputation: 4708

If you can already read the files, just check for all of the newline characters like "\n" and "\r". I'm pretty sure that linux uses "\r\n" as the newline character.

You can read this page: http://en.wikipedia.org/wiki/Newline

and here is a list of all the ascii codes including the newline characters:

http://www.asciitable.com/

Edit: Linux uses "\n", Windows uses "\r\n", Mac uses "\r". Thanks to Seth Carnegie

Upvotes: 1

Adrian Cornish
Adrian Cornish

Reputation: 23916

Since the result will be CR LF, I would add something like the following to consume the extras if they exist. So once your have read you record call this before trying to read the next.

 std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Upvotes: 0

Related Questions