Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Inserting a line at specific point in file

I have a text file that contains the high scores of a game in this format:

Name Score
Name Score
Name Score

With the file ordered in descending order on score.

I want to insert a new name and its corresponding score in the right place in the file so that it remains ordered correctly. Any suggestions how to do this would be greatly appreciated!

For Example, given the following file:

Edward 100
David 90
Sarah 80
Alice 60

And I want to add.

Name = Jodi
Score = 70

To the file, so the new file reads:

Edward 100
David 90
Sarah 80
Jodi 70
Alice 60

Thanks

At the moment I have the following code:

string playerName = pPlayer->GetName();
int playerScore = pPlayer->GetScore();

std::ofstream score("scores.txt", std::ios_base::app | std::ios_base::out);

score << "\n" << playerName << " " << playerScore;

Which just adds the name to the end of the file. I considered reading in the whole file ordering it then Over righting the old file. But I don't want to do this because it could take ages if the file got large.

like image 941
stell1315 Avatar asked Mar 20 '23 23:03

stell1315


2 Answers

There are a few different ways to do this. The one that is simplest to implement is one that reads the entire file into a vector, inserts the new value and writes out the new file.

The second option is to read the file until you find the right place, "mark" where that is in the file (using for example istream::tellg()), then read all the following elements into a vector, update the new record, and write back out the once beyond that.

A third option is to just keep the list unordered in the file, and sort the information when you read it. That way, you can just append to the end, saving on writing the file over and over again.

In reality, I suspect that writing a VERY large file will still be quick enough to make little or no difference at all. Modern hard drives will write many megabytes per second, and you only have some dozens of bytes per line, so you need to have milions of lines in your file before it makes any difference at all. For example, I just copied some large files amounting to 132MB on my machine, and the compined time to read and write 132mb came to 1.2s. If each of your records are 26 bytes, that's 50 million "scores".

like image 68
Mats Petersson Avatar answered Mar 22 '23 13:03

Mats Petersson


If you carefully define a type to represent your data record:

struct Record { 
    std::string name; int score; 
    friend std::istream& operator>>(std::istream& is, Record& r)       { return is >> r.name         >> r.score; }
    friend std::ostream& operator<<(std::ostream& os, Record const& r) { return os << r.name << "\t" << r.score; }

    bool operator<(Record const& other) const {
        return other.score < score;
    }
};

Note that it knows how to

  • read a record from a stream
  • write it back to a stream
  • compare records by score

Then, C++ algorithms are your friend once again:

int main()
{
    std::ifstream ifs("input.txt");
    std::vector<Record> const insert { Record { "Jodi", 70 } };

    std::merge(
            std::istream_iterator<Record>(ifs), {}, 
            insert.begin(), insert.end(),
            std::ostream_iterator<Record>(std::cout, "\n"));
}

See it Live On Coliru

like image 45
sehe Avatar answered Mar 22 '23 14:03

sehe