简体   繁体   English

C中的二进制文件

[英]Binary Files in C

I must do a game in university in C. 我必须在C的大学里做一场比赛。

I'm having real problems with the read and write in binary files. 我在读写二进制文件时遇到了实际问题。

I already asked the monitors, read a chapter about binary files in the book, and tried to search in Google for anything that could help me understand better the problem that I'm having, but none of these worked properly. 我已经问过监视器,阅读了一本书中有关二进制文件的章节,并尝试在Google中搜索可以帮助我更好地了解自己所遇到的问题的任何内容,但是这些都无法正常工作。

There's a struct in the game with all the informations that we need to save to the player restart the game when he likes. 游戏中有一个结构,需要保存至玩家的所有信息才能在玩家喜欢时重新启动游戏。 We must save all the different games in a single one binary file, using the name for recongnition. 我们必须使用确认的名称将所有不同的游戏保存在一个单一的二进制文件中。 So, I did a algorithm that read the binary file, if it exists, and if it find a game with the same name of the player, it overwrite it with the new game, if it does not exist, it will write in the end of the file. 因此,我做了一个算法来读取二进制文件(如果存在),并且如果找到与玩家同名的游戏,则用新游戏覆盖它(如果不存在,它将最终写入)文件。

We must also do the reading of the file for loading a previous game. 我们还必须读取文件以加载以前的游戏。

I did a little program just to test the idea with the struct having only the player's name, but I'm having a problem: when I save, it appears to be working propperly, but when I try to load it, it shows me twice or even three times the name of the player (i putted the command puts with the name in the case the program finds a game saved with the same name). 我做了一个小程序,只是用只有玩家名字的结构来测试这个想法,但是我遇到了一个问题:当我保存时,它似乎工作正常,但是当我尝试加载它时,它显示了两次甚至是玩家名称的三倍(我在程序找到以相同名称保存的游戏的情况下,将命令与名称放在一起)。

Another thing that is puzzling me is that when I save two different games with different names, when I try to load the first one, it shows only one time. 令我感到困惑的另一件事是,当我保存两个具有不同名称的不同游戏时,当我尝试加载第一个游戏时,它只显示一次。

I would really aprecciate any help that you could give me in why this is happening. 我真的很感谢您能为我提供任何帮助,以防止发生这种情况。

My code: 我的代码:

int main()
{
GAME game;
GAME jogoTeste;
FILE *saved_game;
int i = 0;
int choice, saved = 0;

gets(game.player.name);

printf("Choose what you want to do:\n");
printf("1 to save, 2 to load\n");
scanf("%d", &choice);

if (choice == 1)
{
    i = 0;
    saved_game = fopen("saved_game.dat", "a+b");
    rewind(saved_game);
    while (!feof(saved_game))
    {
        fread(&testeGame, sizeof(GAME), 1, saved_game);
        if (!strcmp(testGame.player.name, game.player.name))
        {
            int control = fwrite(&game, sizeof(GAME), 1, saved_game);
            if (control != 1)
            {
                printf("An error happened in the wrintting\n");
                printf("Were written %d elements intead of 1.\n", control);
            }
            else
            {
                saved = 1;
                printf("Player updaded!\n");
            }
        }
    }

    if (saved == 0);
    {
        fwrite(&game, sizeof(GAME), 1, saved_game);
        printf("New player saved\n");
    }
    fclose(saved_game);
}

else if (escolha == 2)
{
    i = 0;
    saved_game = fopen("saved_game.dat", "rb");

    while (!feof(saved_game))
    {
        fread(&testGame, sizeof(GAME), 1, saved_game);

        if (strcmp(testGame.player.name, game.player.name) == 0)
        {
            puts(testGame.player.name);
        }
    }
    fclose(saved_game);
}

}

and the struct GAME is (the other ones are not that important here): 而struct GAME是(其他在这里不是那么重要):

typedef struct
{
    PLAYER player;
    GUARD guards[5];
    KEY keys[5];
    COORDINATE walls[50];
    COORDINATE tower[50];
    COORDINATE ogre;
} GAME;

If there is anyhing in portuguese is because I didn't see it right now and just forget to translate it for here. 如果葡萄牙语中有任何内容,是因为我现在没有看到它,而忘了在这里翻译。 I'm sorry 对不起

EDIT: I tried some alterations that you mentioned and the error that duplicated my loading game are gone, but there is something that is really puzzling my head right now, my code that saves the game right now is: 编辑:我尝试了您提到的一些更改,并且复制了加载游戏的错误消失了,但是现在确实有些事情令人困惑,我现在保存游戏的代码是:

saved = 0;
    saved_game = fopen("saved_game.dat", "r+b");
    while (fread(&jogoTeste, sizeof(GAME), 1, saved_game))
    {
        if (strcmp(jogoTeste.player.name, game.player.name) == 0)
        {
            fseek(saved_game, currentOffSet, SEEK_SET);

            control = fwrite(&game, sizeof(GAME), 1, saved_game);

            if (control != 1)
            {
                printf("An error happened in the wrintting\n");
                printf("Were written %d elements intead of 1.\n", control);
            }
            else
            {
                saved = 1;
                printf("Player updated!\n");
            }

            fseek(saved_game, 0, SEEK_END);
        }
        currentOffSet = ftell(saved_game);
    }

    if (!saved);
    {
        fwrite(&game, sizeof(GAME), 1, saved_game);
        printf("New player saved\n");
    }
    fclose(saved_game);

But when I execute it, it gives me in the screen: "Player updated!" 但是,当我执行它时,它会在屏幕上显示:“播放器已更新!” AND "New player saved", how can it be? AND“新玩家已保存”,怎么可能? When it updates the player, it also changes the variable saved to 1, and there is the if before the "New player saved" just for that. 更新播放器时,它还会将保存的变量更改为1,并且在“保存新播放器”之前有一个if。 How can it be executing two parts that shouldn't be? 如何执行不应执行的两个部分?

In your code 在你的代码中

    fread(&testeGame, sizeof(GAME), 1, saved_game);
    if (!strcmp(testGame.player.name, game.player.name))
    {
        int control = fwrite(&game, sizeof(GAME), 1, saved_game);

After you fread, the file pointer has moved forward, then you fwrite after where the fread was. 读取之后,文件指针向前移动,然后在读取的位置之后进行fwrite。 You need to move the file pointer back to overwrite the old record ie use ftell to get where you are then go fseek to go back to that spot or alternatively use fseek to move relative to your current file position back sizeof(GAME) bytes. 您需要将文件指针移回以覆盖旧记录,即使用ftell获取您要去的位置,然后转到fseek返回该位置,或者使用fseek相对于当前文件位置向后移动sizeof(GAME)字节。

eg 例如

    currentOffset = ftell(saved_game);
    fread(&testeGame, sizeof(GAME), 1, saved_game);
    if (!strcmp(testGame.player.name, game.player.name))
    { 
        fseek(saved_game, currentOffset, SEEK_SET);
        int control = fwrite(&game, sizeof(GAME), 1, saved_game);

The main problem is the while(!feof(...)){} construct. 主要问题是while(!feof(...)){}构造。 This performs a random number of appends due to a race condition. 由于竞争条件,这会执行随机数量的追加。 The simple fix is to remove the loop altogether. 简单的解决方法是完全删除循环。 A number of other problems with the code probably will not affect its operation, although should be fixed as a matter of good practice (using getc , superfluous rewind , etc., see the comments). 该代码的许多其他问题可能不会影响其操作,尽管应将其作为一种良好实践来解决(使用getc ,多余的rewind等,请参见注释)。

EDIT: the OP changed the code after some discussion so removing the loop as suggested above is not going to work. 编辑:OP经过一些讨论后更改了代码,因此按上述建议删除循环将无法正常工作。 The proper fix is to separate the reading the file to look for the name of the player, maybe setting a boolean flag, and then perform an append if the boolean is set. 正确的解决方法是分开读取文件以查找播放器的名称,可能设置一个布尔标志,然后在设置了布尔值的情况下执行追加操作。

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

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