Am trying to make a function that displays the last 10 lines of a file and I thought the way to do this is to read the file backwards using seekg and ios::beg but its not working I think am in the right direction but i need some tips on how i can fix this.
What has recsize to do with filename? sizeof(filename) will return the size of the string object not the content (which would be filename.size()). But again: How could the size of filename be related to the size of the record?
The problem with your approach is that you cannot determine the postition to start if you don't know the exact record size.
One approach could be:
Read 10 lines (determined be counter). If you reach the limit each line is moved on position toward the fromt until the first line which is dismissed. In a second loop show the remaining 10 lines.
Another approach:
Read all lines in a vector and show the last 10 only.
#include<fstream>
#include<sstream>
#include<string>
#include<cstdlib>
#include<iostream>
readFile(const std::string& filePath, std::string& fileContent) {
std::ifstream inFile(filePath, std::ios::binary);
if (inFile.is_open()) {
autoconst start_pos{ inFile.tellg() };
inFile.ignore(std::numeric_limits<std::streamsize>::max());
std::streamsize char_count{ inFile.gcount() };
inFile.seekg(start_pos);
fileContent = std::string(static_cast<std::size_t>(char_count), '0');
inFile.read(&fileContent[0], static_cast<std::streamsize> (fileContent.size()));
inFile.close();
}//end of if
else {
std::cout << "Unable to open file\n";
std::exit(EXIT_FAILURE);
}//end of else
}
this code is safe and fast for big files.
What i would advice to do is:
-each line has a \n at the end right?
So once you finish reading the file just count the \n from the end until you hit 10 and than just std::cout the substring which conrains the 10 lines.
I am by no means an expert and surely it can be done better but this is the safest way i know of. Good luck :)
@Thomas1965
Your way is simpler i believe, although we recommended almost the same thing :)
Just have one question i asked in another post:
Wouldn't an std::deque<char> be faster for that purpose ? if he doesn't reserve space for vector it will severely impact performance on long lines as many allocations must be made in the process.
I like @Thomas1965's idea, but here are some other ideas:
- read the file line by line into strings and keep a rolling container of the last (up-to) 10 strings;
- do something clever with stream iterators? (I don't actually know what!)
I tried seekg and searching for \n to save having to store an entire file and read large files only once:
#include <iostream>
#include <fstream>
usingnamespace std;
int main()
{
constint NUMLINES = 10;
char c;
ifstream in( "temp.cpp", ios::binary );
in.seekg( -1, ios::end ); // position to read last character
int counter = -1; // assumes that you will pick up a NL at end of file
while ( counter < NUMLINES )
{
in.get( c );
if ( !in ) { in.clear(); in.seekg( 0, ios::beg ); break; } // deal with <= NUMLINES or not found
if ( c == '\n' ) counter++; // found a new line
if ( counter != NUMLINES ) in.seekg( -2, ios::cur ); // move back to previous character
}
c = in.peek(); if ( c == '\r' ) in.seekg( 1, ios::cur ); // deal with CR-LF
while ( in.get( c ) ) cout.put( c ); // output rest of file
}
One based on @Thomas1965's idea. I have to admit, it's easier to understand.
It has plenty of advice on file reading and why it should be done certain ways.
I tried seekg and searching for \n to save having to store an entire file and read large files only once:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
const int NUMLINES = 10;
char c;
ifstream in( "temp.cpp", ios::binary );
in.seekg( -1, ios::end ); // position to read last character
int counter = -1; // assumes that you will pick up a NL at end of file
while ( counter < NUMLINES )
{
in.get( c );
if ( !in ) { in.clear(); in.seekg( 0, ios::beg ); break; } // deal with <= NUMLINES or not found
if ( c == '\n' ) counter++; // found a new line
if ( counter != NUMLINES ) in.seekg( -2, ios::cur ); // move back to previous character
}
c = in.peek(); if ( c == '\r' ) in.seekg( 1, ios::cur ); // deal with CR-LF
while ( in.get( c ) ) cout.put( c ); // output rest of file
}