C++ – Reading a File through get, getline and read : C++

c++ifstream

I am trying to explore ifstream class and have written below code which reads a file Test.txt

'Test.txt' – Content

This is Line One
This is Line Two
This is Line Three
This is Line Four
This is Line Five

Code Written:

#include <iostream>
#include <fstream>
#include <limits>

using namespace std;

int main()
{

    char buff[50];

    char ch;
    ifstream is("test.txt");
    if (!is)
    cout << "Unable to open " << endl;

    while(is)
    {
        ch=(char)is.get();
        if(ch != EOF)//If EOF is not checked then
        //EOF converted as a char is displyed as
        // last char of the file
        cout << ch;
        }


    cout << "\n\n###########\n\n";
    is.clear(); //clearing ios_base::eofbit which was set 
    //in previous action
    is.seekg(0,ios_base::beg); //Going back to start of File

   while(is)
   {

     is.get(buff,50,'\n');
     cout << buff ;
     cout << "\n--------------\n";
     is.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
     //Flushing the is stream as '\n' was left by get fn
   }


  cout << "\n\n@@@@@@@@@@@@@@\n\n";
    is.clear();
    is.seekg(0,ios_base::beg);

    while(!is.eof())
    {
        is.getline(buff,50,'\n');
        cout << buff;
        cout << "\n--------------\n";
        //No need to flush the is stream as '\n' 
        //was extracted and discarded by getline
        }

    cout << "\n\n$$$$$$$$$$$$$$\n\n";
    is.clear();
    is.seekg(0,ios_base::end);
    int size=is.tellg();
    is.seekg(0,ios_base::beg);
    cout << "size : " << size << endl;

    //char* readBuff = (char *) ::operator new(sizeof(char)*size);
    char* readBuff = new char[size];
    is.read(readBuff,size);
    cout << readBuff;
    delete(readBuff);

    is.close();

    return 0;
    }

OutPut:

Gaurav@Gaurav-PC /cygdrive/d/Trial
$ ./Trial
This is Line One
This is Line Two
This is Line Three
This is Line Four
This is Line Five

###########

This is Line One
--------------
This is Line Two
--------------
This is Line Three
--------------
This is Line Four
--------------
This is Line Five
--------------


@@@@@@@@@@@@@@

This is Line One
--------------
This is Line Two
--------------
This is Line Three
--------------
This is Line Four
--------------
This is Line Five
--------------


$$$$$$$$$$$$$$

size : 92
This is Line One
This is Line Two
This is Line Three
This is Line Four
This is Line Five▒u

There are some issues which I want to ask and get clarified:

1) When I use get as below

   while(is)
   {

     is.get(buff,50,'\n');
     cout << buff ;
    // cout << "\n--------------\n";
     is.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
     //Flushing the is stream as '\n' was left by get fn
   }

i.e. I commented out cout << "\n--------------\n"; then the file is read as

###########

This is Line Fivee

i.e. it misses first four lines and reads only last one with extra 'e' .. not able to figure out why so ?

2) When I use getline as below:

// while(!is.eof())
   while(is)
    {
        is.getline(buff,50,'\n');
        cout << buff;
        cout << "\n--------------\n";
        //No need to flush the is stream as '\n'
        //was extracted and discarded by getline
        }

i.e. I used while(is) instead of while(!is.eof()) – I got the output:

@@@@@@@@@@@@@@

This is Line One
--------------
This is Line Two
--------------
This is Line Three
--------------
This is Line Four
--------------
This is Line Five
--------------

--------------

i.e. after the last line I get two extra lines. Again not able to figure out why so?

3) With read function the size I am getting is 92 where as total number of charaters in the file is 89 including EOF,spaces and '\n'. Also the last line shows two garbage characters after rearing the last character of the file. Why such behavior?

cout << "\n\n$$$$$$$$$$$$$$\n\n";
is.clear();
is.seekg(0,ios_base::end);
int size=is.tellg();
is.seekg(0,ios_base::beg);
cout << "size : " << size << endl;

//char* readBuff = (char *) ::operator new(sizeof(char)*size);
char* readBuff = new char[size];
is.read(readBuff,size);
cout << readBuff;
delete(readBuff);

OutPut:

$$$$$$$$$$$$$$

size : 92
This is Line One
This is Line Two
This is Line Three
This is Line Four
This is Line Five▒u

Thanks

EDIT:

As Per Answer received by Mats Peterson , I tried below code:

while(is.get(buff,50,'\n'))
   {
     cout << buff ;
     //cout << "\n--------------\n";
     is.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
     //Flushing the is stream as '\n' was left by get fn
   }


  cout << "\n\n@@@@@@@@@@@@@@\n\n";
    is.clear();
    is.seekg(0,ios_base::beg);

   // while(!is.eof())
   while(is.getline(buff,50,'\n'))
    {

        cout << buff;
        //cout << "\n--------------\n";
        //No need to flush the is stream as '\n'
        //was extracted and discarded by getline
        }

But got the output:

###########

This is Line Fivee

@@@@@@@@@@@@@@

This is Line Fivee

i.e Only Last line read… if I uncomment //cout << "\n--------------\n"; I get proper reading

@Down Votes At least comment what made you do so? I faced this issue that is why asked here to gain more insight from experts..

Best Solution

In the first two questions, you are because you are reading "one more than you have", which is a typical consequence of "the failure state is not set until we have tried to read past the end". This is why you should use

 while(is.get(... ))
 while(is.getline(...))

as the condtions for ending loops - because that will not run the loop when the read fails.

The third issue is because Windows used "CR+LF" for newlines, where reading a file in text mode (which is the default) collapses these into a single newline character. So the size of your file according to is.tellg is larger by one character for each newline than the data you actually read. You can use is.gcount() to see how many characters you ACTUALLY read. (and if (!is.read(... )) actual = is.gcount(); else actual = size; should give you a complete piece of code).

Related Question