I have been reading up on this forum looking for answers to my own questions but i find myself stumpped. I basically have to read from a file the last ten lines of input. Yes this is for a homework assignment and i have spent hours on it reading my book and googleing my eyes off. I can open the file, i have found a way to get the total line numbers. I am just totally lost as to how to read the last ten lines only. I have looked into random access but thats in bytes and i dont see how that could work as it should be able to read the last ten lines of any file. Am i missing something? Any help would be greatly appreciated.

#include <cstdlib>
#include <iostream>
#include <fstream>


using namespace std;

bool openFile(fstream &);
int getLines(fstream &);
int readLines(fstream &);

char fileName[20];
char * fileNameptr = fileName;
int totalLines = -1;                                  

int main(int argc, char *argv[])
{
    fstream dataFile;
    
    if(!openFile(dataFile))
    {
        cout << "Error opening file...closing" << endl;
        return 0;                   
    }
    
    getLines(dataFile);
    
    cout << "Total Lines: " << totalLines << endl;
    
    readLines(dataFile);
    
    system("PAUSE");
    
    return EXIT_SUCCESS;
}

bool openFile(fstream &file)
{    
     cout << "Please enter the file name" << endl;
     cin >> fileName;
     
     file.open(fileNameptr, ios::in);
     if(!file)
     {
         return false;           
     }    
     else
     {
         file.close();
         return true;
     }
}

int getLines(fstream &file)
{
     const int SIZE = 81;
     char input[SIZE];
     string line [SIZE];   
    
     file.open(fileNameptr, ios::in);
     if(!file)
     {
          cout << "Error opening file" << endl;
          return 0;
     }
    
     file.getline(input, SIZE);
     while(!file.eof())
     { 
            totalLines ++;
            file.getline(input, SIZE);            
     }
     file.close();
}
   
int readLines(fstream &file)
{
     file.open(fileNameptr, ios::in);
     if(!file)
     {
          cout << "File open error" << endl;
          return 0;         
     }    
     
     double numBytes;
     char ch;
     
     file.seekg(0L,ios::end);
     numBytes = file.tellg();
     cout << "The file has " << numBytes << " bytes." << endl;
    
     file.clear();
    
     file.seekg(0L, ios::beg);
     file.get(ch); 
     cout << "ch: " << ch << endl;

}

How about this:

let the number of lines you counted be "N". Now, do this:

// advance to last 10 lines. 
while (count != (N - 10)) {
     char c = file.get();
     if (c == '\n')
           count++;
}

I rethought the problem with your advise in mind and i came up with this. What do you think?

#include <cstdlib>
#include <iostream>
#include <fstream>


using namespace std;

bool openFile(fstream &);
int getLines(fstream &);
int readLines(fstream &);

char fileName[20];
char * fileNameptr = fileName;
int totalLines = -1;                                  

int main(int argc, char *argv[])
{
    fstream dataFile;
    
    if(!openFile(dataFile))
    {
        cout << "Error opening file...closing" << endl;
        return 0;                   
    }
    
    getLines(dataFile);
    
    cout << "Total Lines: " << totalLines << endl;
    
    readLines(dataFile);
    
    system("PAUSE");
    
    return EXIT_SUCCESS;
}

bool openFile(fstream &file)
{    
     cout << "Please enter the file name" << endl;
     cin >> fileName;
     
     file.open(fileNameptr, ios::in);
     if(!file)
     {
         return false;           
     }    
     else
     {
         file.close();
         return true;
     }
}

int getLines(fstream &file)
{
     const int SIZE = 81;
     char input[SIZE];
     string line [SIZE];   
    
     file.open(fileNameptr, ios::in);
     if(!file)
     {
          cout << "Error opening file" << endl;
          return 0;
     }
    
     file.getline(input, SIZE);
     while(!file.eof())
     { 
            totalLines ++;
            file.getline(input, SIZE);            
     }
     
     file.close();
}
   
int readLines(fstream &file)
{
     const int SIZE = 81;
     char input[SIZE];
    
     file.open(fileNameptr, ios::in);
     if(!file)
     {
          cout << "File open error" << endl;
          return 0;         
     }    
     
     int uselessLines = totalLines-10;   
     int readLines = totalLines- uselessLines;
     
     cout << "useless: " << uselessLines << endl;
     cout << "read: " << readLines << endl;
     
     for(int i  = uselessLines;i>0;i--)
     {
           file.getline(input,SIZE);        
     }
     
     for(int i = readLines;i>0;i--)
     {
           file.getline(input,SIZE);  
           cout << input;    
     }
}

Only problem is that my code is not rendering any output from the textfile.txt through cout << input in the last for loop. Do you know why that would be?

There are two functions that are _crucial_ for doing random access into a file stream, that is: tellg and seekg. The first will tell you at what position the reading pointer (g) is at the moment and the second will take that pointer to a previously recorded place (obtained from tellg). This allows you to parse the file and "remember" important places, like the start of the tenth last line.

You managed to get a pretty good solution. The only problem is that if you have thousands of lines before the last ten lines, you have to read through the entire file instead of just skipping straight to the end. Here is a somewhat better solution:

#include <cstdlib>
#include <iostream>
#include <fstream>


using namespace std;

bool openFile(fstream &);
int getLines(fstream &);
int readLines(fstream &);

char fileName[20];
char * fileNameptr = fileName;
int totalLines = 0; // I am pretty sure this should start at 0.

streampos tenthLastLine; //use a stream position variable for the tenth last line.

int main(int argc, char *argv[])
{
    fstream dataFile;
    
    if(!openFile(dataFile))
    {
        cout << "Error opening file...closing" << endl;
        return 0;                   
    }
    
    getLines(dataFile);
    
    cout << "Total Lines: " << totalLines << endl;
    
    readLines(dataFile);
    
    system("PAUSE");
    
    return EXIT_SUCCESS;
}

bool openFile(fstream &file)
{    
     cout << "Please enter the file name" << endl;
     cin >> fileName;
     
     file.open(fileNameptr, ios::in);
     if(!file)
     {
         return false;           
     }    
     else
     {
         file.close();
         return true;
     }
}

int getLines(fstream &file)
{
     const int SIZE = 81;
     char input[SIZE];
     string line [SIZE];   
    
     file.open(fileNameptr, ios::in);
     if(!file)
     {
          cout << "Error opening file" << endl;
          return 0;
     }

     //store the last 10 positions in a rolling array:
     streampos lastPos[10];
     
     lastPos[0] = file.tellg();
     file.getline(input, SIZE);
     while(!file.eof())
     { 
            totalLines ++;
            lastPos[totalLines % 10] = file.tellg(); //keep a rolling record of last 10 line start positions.
            file.getline(input, SIZE);            
     }

     //now the tenth last line is one rolling position after the last recorded position.
     if(totalLines > 9)
       tenthLastLine = lastPos[(totalLines+1) % 10];
     else
       tenthLastLine = lastPos[0];

     //file.close(); //keep the file open.
}
   
int readLines(fstream &file)
{
     const int SIZE = 81; //make it bigger and power of 2. Wassup with 81?
     char input[SIZE];
    
     //file.open(fileNameptr, ios::in); //file is already open;
     
     //now just seek to the position and start reading:
     file.seekg(tenthLastLine);
     for(int i = 10; ((i>0) && (!file.eof())) ;i--)
     {
           file.getline(input,SIZE);  
           cout << input << endl;
     }

     file.close();
}

Of course, if you merge the two functions, you can just keep a rolling record of the last ten lines and print them out at the end, this way you read the file only once.

Edited 6 Years Ago by mike_2000_17: n/a

About the rendering of the lines at the end, I believe the newline character is not part of the characters that are written to "input" by the function getline(). So the output buffer, which flushes on newlines, never flushes before the application reaches the end. Just add " << endl;" in that printing line of the last for-loop.

Thank you so much for the detailed responce. Alot of that stuff you are doing is upper level programming and i have not touched on a streampos or anything like that. I never though about the file being 1000+ lines. Very clever solution.

I have one more question and it might be complier related. I cannot get my file or your file to output any text. I was using xocde on my mac side and i was having all kinds of problems with it so i switched to the windows side and am not useing dev c++ as my compiler.

I can not get any output from "cout << input" on my screen. My computer is obvisously opening the textfile as i can get the line count and such but i have no idea why i cannot see the output from "cout << input" does anyone have any idea what that could possible be?

Oh, yeah, I understand. The problem is that once you reach end-of-file (eof) then you cannot read with the file again because it goes in this error state that prohibits any further file operations. To reset the state, call "file.clear();" at the start of the readLines() function. That should fix it, and don't forget the "endl" on the output.

This question has already been answered. Start a new discussion instead.