Unfortunately in c++, there is really no good way go locate lines in your file without reading the entire file 'character at a time.'

So, if you have to read only a single line from a file, we know we are at some point going to have to be inefficient... so let's only be inefficient once. The following code traverses the entire file once, char at a time, but saves the positions of all '\n' new lines... so any queries for specific lines from the file can be made efficiently:

#include<iostream>
#include<cctype>
#include<fstream>
#include<string>
#include<vector>

using namespace std;

int main()
{
    int linecount = 0;
    int linetoget = 0;
    int pos = 0;
    char c = '\0';
    char again = '\0';
    string line_str;
    vector<int> linepos;
    ifstream infile;

//Be sure to open in binary mode when messing about with file pointers    
infile.open("C:\\Users\\Dave\\Documents\\resume.txt", ios::binary);

    if(!infile.is_open())
    {
        cout << "\a\nError opening file!";
        cin.get();
        exit(1);
    }

    //Set first line position
    linepos.push_back(0);
    linecount++;

    //Populate line positions from the rest of file
    //This part sucks, but we only have to do it once.
    do{
        infile.get(c);
        if(c == '\n')
        {
            pos = infile.tellg();
            linepos.push_back(pos);
            linecount++;
        }
    }while(infile.good());

    //Reset error flags from the failing good() condition
    infile.clear();

    do{
        do{
            cout << "\nEnter line of file to get: ";
            cin >> linetoget;

            if(linetoget < 1 || linetoget > linecount)
            {
                cout << "\a\nOut of Range.  Please select line number 0 to " << linecount << endl;
            }
        }while(linetoget < 1 || linetoget > linecount);

        infile.seekg(linepos[linetoget-1], ios::beg);
        getline(infile, line_str);

        //clear fail bit flag if use selects to read the last line (reads and sets eof)
        infile.clear();

        cout << endl << line_str << endl;

        cout << "\nWould you like to get another line? ";
        cin >> again;

    }while(toupper(again) == 'Y');

    infile.close();

    return 0;
}

We know we have to be very inefficient by reading the file character by character.. but at least by saving all the newline positions, it's something we only have to do once.

Recommended Answers

All 3 Replies

That is also a good solution.. reading line at a time into a string, clearing the string until you find the one you want.

However, this implementation will require multiple visits back to the file in order to find additional lines requested by the user.

With my implementation, once you pay the price at the beginning, any queries for lines are made very efficiently.. no additional searching needed.

I would just like to say one more thing about this technique...

I'm gonna throw out some figures here, feel free to argue their validity...

I would guess that a file loaded into memory is probably accessed less than 1% of the time they are loaded into memory.. the remaining 99% of the time, the loaded file just sits in your memory card, just taking up space (which my ex wife would argue would be similar to my performance.)

Having the ability to access your file on demand can allow you to free up a block of memory that can last the entire life span of your running application.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.