display tail of the file

Write a program that should display the last 5 lines of the file on the screen.

this program works well till the end, except the last part of the program. where while(file.eof()) is mentioned. It doesn't display the last five lines of the file. I am not getting how to get the display of it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int main()
{
	fstream file;
	file.open("name.txt", ios::in);
	
	if(file.fail())
	{
		cout<<"file is not opened and processing failed"<<endl;
	}
	
	int n=0;
	int pos=-1;
	char ch;
	string str;
	file.seekg(0L, ios::end);
	
	while(n!=5)
	{
		file.seekg(pos, ios::cur);
		pos--;
		
		file.get(ch);
		if(ch=='\n')
		{
			n++;
		}
	}
	cout<<n<<endl;
	
	while(file.eof())
	{
		getline(file, str);
		cout<<str<<endl;
	}
}
Last edited on
1
2
while(getline(file, str))
   cout << str << endl;



> while(file.eof())
read out loud: «while the file is at the end»
but you want: «while the file did not reach the end»
still, the check would be too late, just loop on the reading operation.
seek end and read backwards... you don't want to spend 2 min to find the last 5 lines of a 10gb xml file... which you did, but reading backwards is not going to hit end of file, now is it? You need a better mousetrap for what to do with a 3 line file (how to stop and what to do).

here is my real quick take on it. it could be better. we basically see how many bytes are in the file, read it backwards into a string until we run out of bytes or find 5 end of lines (eoln = 10 or 10/13 for most OS). then reverse the string and you have it. For all I know there is some c++20 way to read backwards; this is kind of brutish.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int main()
{
  ifstream ifs("x");
  ifs.seekg(0, ios::end);  
  int len = ifs.tellg();    
  streampos sp = len;  
  string s;  
  
  for(int i = 1, ct = 0; i<=len && ct !=5; i++)
  {
	sp = len-i;
	ifs.seekg(sp);
    if(ifs.peek() == 10)
	{
      ct++;
	}
    s+= ifs.peek();  	  
  }
  reverse(s.begin(), s.end()); 
  cout << s;  
}
Last edited on
Dear ne555
I just changed the code little bit kindly suggest how to improve it.

Dear Jonnin
I have used seekg for finding out the '\n' space and right after that getline and displayed it, but facing same issue. Kindly explain what should I do.
regards

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int main()
{
	fstream file;
	file.open("name.txt", ios::in);
	
	if(file.fail())
	{
		cout<<"file is not opened and processing failed"<<endl;
	}
	
	cout<<"file opened"<<endl;
	int counter=0;
	int position=-1;
	char ch;
	string str;
	
	file.seekg(0L, ios::end);s
	while(counter!=5)
	{
		file.seekg(position, ios::cur);
		
		file.get(ch);
		if(ch=='\n')
		{
			counter++;
		}
		
		getline(file, str);
		cout<<str<<endl;
		position--;	
	}
}
you are making this too hard.
you assume the file has 5 lines. it need to work on a 3 line file, or even a file with no end of lines, etc.
position -- only moves 1 byte, but getline affects many. This is not logically compatible.
I had trouble with seek until I changed it to use the streampos type. It did not like integers on my implementation. Dunno if that is something I did wrong or something my compiler did wrong... didn't dig into it, just changed types and kept going.

I mean, say your file is this, and x means end of line, z means EOF
00x
11x
22x
33x
44x
55z
so you find the first x between 4 and 5. then you getline, and that reads 55 (or, not 100% sure, being ON the eoln maybe it reads empty line?) and sets your position back to the end of file. (or the start of 55?) then you subtract 1. then you getline again. Does that logic seem correct (hint, the answer is no).

what I gave you works, though crude. if you want to use end of line, you need to adjust by the length of the strings you found and correct your logic.
here is a real fast crack at doing it via end of line. it didn't work for a file with 2 back to back eolns at the end, and I don't have time to debug it, but its a starting point. You can see it is more trouble.. you have to double getline and check to get the first line if < 5 were found, and more. These extra issues make it harder to get exactly right...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int main()
{
  ifstream ifs("x");
  ifs.seekg(0, ios::end);  
  int len = ifs.tellg();    
  streampos sp = len;  
  string s, s2;  
  
  int ct = 0;
  for(int i = 1; i<=len && ct !=5; i++)
  {
	sp = len-i;
	ifs.seekg(sp);
    if(ifs.peek() == 10)
	{
      ct++;
	  getline(ifs,s);	  
	  getline(ifs,s);
	  cout << s << endl;
	}	
  }  
	if(ct != 5) 
	{
		getline(ifs,s);
		cout << s << endl;
	}
}
Last edited on
Thankyou so Much Jonin for explaining in detail.

Regards.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

vector<string> lastLines( string filename, int N )
{
   vector<string> S( N );
   ifstream in( filename );
   int pos = 0;
   string line;
   while( getline( in, line ) )
   {
      S[pos] = line;
      pos++;
      if ( pos == N ) pos = 0;
   }
   rotate( S.begin(), S.begin() + pos, S.end() );
   return S;
}


int main()
{
   const int N = 5;
   vector<string> L = lastLines( __FILE__, N );
   for ( string &s : L ) cout << s << '\n';
}


{
   const int N = 5;
   vector<string> L = lastLines( __FILE__, N );
   for ( string &s : L ) cout << s << '\n';
}
Last edited on
thankyou so much lastchance....
Topic archived. No new replies allowed.