简体   繁体   English

用ofstream C ++覆盖一行

[英]Overwrite a line with ofstream C++

I am doing a little game and I am saving the player details in a txt file. 我正在做一个小游戏,并将玩家详细信息保存在txt文件中。 Example of that txt file: 该txt文件的示例:

Eric 13 8 10 10 30 10 10 50 0 0 0 0
William 1 0 10 30 30 10 10 50 0 0 0 0
John 1 0 10 30 30 10 10 50 0 0 0 0

This is what I had in mind: when the player chooses to save the game while playing, the save_game function should check if there is already any saved data. 这就是我的初衷:当玩家选择在玩游戏时保存游戏时, save_game函数应检查是否已经有保存的数据。 If there is, instead of appending the data to the end of the txt, it should overwrite that specific line. 如果有的话,它应该overwrite该特定行,而不是将数据附加到txt的末尾。

Here is my current function: 这是我当前的功能:

// SAVE GAME
void save_game(Player player)
{
    ofstream coutfile (SaveDestiny, ios::app);

    if (coutfile.is_open()) // if it opens correctly
    {
        // Now checking if the name already exists
        string imported_name;

        ifstream cinfile (SaveDestiny); // opens file that contains the saved games

        cinfile >> imported_name; // getting first element of file

        bool j = 0; // j = 0 while the strings don't match. j = 1 when the string was found

        while (cinfile >> imported_name) // while the end of file is not reached
        {
            if (player.name.compare(imported_name) == 0) // if the strings are the same, overwrite data
            {
                j = 1;

                coutfile << "                                                                         \r" << endl;
                break;
            }
            else // if the strings are different, keep reading
            {
                cinfile >> imported_name;
            }
        }

        // Continuing...
        coutfile << player.name << " " << player.level << " " << player.exp << " " << player.max_exp << " "
            << player.hp << " " << player.max_hp << " " << player.mp << " " << player.max_mp << " "
            << player.gold << " " << player.weapon << " " << player.shield << " " << player.heal_spell << " "
            << player.attack_spell << endl;
    }
    else
    {
        ofstream coutfile (SaveDestiny, ios::app);
        coutfile << "test";
        cout << "Unable to open file";
        cin.get();
    }

    draw_rectangle(37,8,72,14,15);  // white limits
    draw_rectangle(39,9,70,13,9);   // blue background
    cor(9,15);
    gotoxy(50,10);
    cout << "GAME SAVED!";
    gotoxy(41,12);
    cor(9,14);
    cout << "Press <Enter> to continue... ";
    cin.get();
}

On most modern filesystems files are not "line-based" (or "record-based") they are character-based so you can't "overwrite a line". 在大多数现代文件系统上,文件不是基于行的(或基于记录的),而是基于字符的,因此您不能“覆盖行”。 The old line might be 20 characters long and the new one would be 24 characters, in which case it would overwrite the old line and the first 4 characters of the next line. 旧行可能长20个字符,而新行可能长24个字符,在这种情况下,它将覆盖旧行下一行的前4个字符。 To make this work you would have to "push" everything after the line later in the file, which isn't possible with C++ (or C) IO facilities. 为了使这项工作有效,您将不得不在文件后面的行之后“推送”所有内容,而这对于C ++(或C)IO设备是不可能的。

One option would be to write all lines with a fixed length, say 50 characters, so that overwriting the 3rd line involves replacing characters 100 to 149, even if the line only actually needs 24 characters. 一种选择是将所有具有固定长度的行(例如50个字符)写入,以便覆盖第三行涉及将字符替换为100到149,即使该行实际上只需要24个字符也是如此。

Another option would be to keep the file in memory in a record-based form and write out the entire file every time you change it (or at least write out the new line and all lines that come after it) 另一种选择是将文件以基于记录的形式保存在内存中,并在每次更改时写出整个文件(或至少写出新行及其后的所有行)

Ok I've managed to get around the problem and now it's working brilliantly! 好的,我设法解决了这个问题,现在它的工作非常出色! :D :D

First, the function checks if the player name already is on the txt . 首先,该function检查播放器名称是否已经在txt I created a enable variable j . 我创建了一个启用变量j When j=1 , the name exists and the data needs to be overwritten ! j=1 ,名称存在并且数据需要被overwritten When j=0 , the function will append the data to the txt right away. j=0 ,函数将立即append数据append到txt。

Ok, let's say j=1 . 好的,假设j=1 The function determines the number of lines in txt . 该函数确定txt的行数。 It then creates a vector with two vectors inside: the name , and the game variables . 然后创建一个vector里面两个向量:该name ,以及game variables After that, the function deletes the previouscontent of txt file. 之后,该函数删除txt文件的先前内容。 And writes the content of the vector to the txt , except the data that needs to be overwritten (it will skip writing that part to the txt ), because at the end of the function, that new data will be written. 并将向量的内容写入txt ,但需要覆盖的数据除外(它将跳过将该部分写入txt ),因为在函数结束时,将写入新数据。 :DI hope I made myself clear enough. :DI希望我让自己说得足够清楚。 Sorry if someone doesn't understand what I wrote... 抱歉,如果有人听不懂我写的话...

Here is my new save_game function: 这是我新的save_game函数:

// SAVE GAME
void save_game(Player player)
{
    ofstream coutfile (SaveDestiny, ios::app);

    if (coutfile.is_open()) // if it opens correctly
    {
        string imported_name;
        ifstream cinfile (SaveDestiny); // opens file that contains the saved games

        bool j = 0;

        // Now checking if the name already exists
        while (cinfile >> imported_name) // while the end of file is not reached
        {
            if (player.name.compare(imported_name) == 0) // if the strings are the same, overwrite data
            {
                j = 1; // enable overwrite
                break;
            }
            // if the strings are different, keep reading
        }
        // at this point: j = 0 to append to end. j = 1 to overwrite.

        // Overwriting data
        if (j == 1)
        {
            ifstream cinfile (SaveDestiny);

            // now determining the size of the vector (number of lines in txt)
            int line_numbers = 0;
            string line;
            while (getline(cinfile, line))
            {
                line_numbers++;
            }

            cinfile.close();    // closing
            ifstream cinfile2 (SaveDestiny);    // reopening to read from the beginning 

            // now creating the vector with the saves
            vector<vector<string>> temp_saves(line_numbers, vector<string>(2));
            string name2;
            string values;

            for (unsigned int x = 0; x < temp_saves.size(); x++)
            {
                cinfile2 >> name2;
                getline(cinfile2, values);

                temp_saves[x][0] = name2;
                temp_saves[x][1] = values;
            }

            coutfile.close(); // closing output file
            ofstream coutfile2 (SaveDestiny); // reopening in overwrite mode

            // delete all saves.txt, copying vector content to txt (except the one we want to overwrite)
            for (unsigned int x = 0; x < temp_saves.size(); x++)
            {
                if ( temp_saves[x][0].compare(player.name) != 0)
                {
                    coutfile2 << temp_saves[x][0] << temp_saves[x][1] << endl;
                }
            }
            coutfile2.close(); // closing output file
        }

        // Appending new data...
        ofstream coutfile3 (SaveDestiny, ios::app); // reopening in append mode
        coutfile3 << player.name << " " << player.level << " " << player.exp << " " << player.max_exp << " "
            << player.hp << " " << player.max_hp << " " << player.mp << " " << player.max_mp << " "
            << player.gold << " " << player.weapon << " " << player.shield << " " << player.heal_spell << " "
            << player.attack_spell << endl;
    }
    else
    {
        ofstream coutfile (SaveDestiny, ios::app);
        cout << "Unable to open file";
        cin.get();
    }

    draw_rectangle(37,8,72,14,15);  // white limits
    draw_rectangle(39,9,70,13,9);   // blue background
    cor(9,15);
    gotoxy(50,10);
    cout << "GAME SAVED!";
    gotoxy(41,12);
    cor(9,14);
    cout << "Press <Enter> to continue... ";
    cin.get();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM