You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

写入结构体到二进制文件后后续结构体丢失问题求助

解决二进制文件写入结构体后后续数据丢失的问题

我帮你排查了代码里的几个关键错误,这就是导致目标结构体之后的数据消失的原因:

问题根源拆解

1. 读取位置计算错误

你在读取玩家数据的循环里用了readstream.seekg(i, ios::beg),这里的偏移量应该是i * sizeof(player)才对。每个playerint类型(占4字节左右),直接用i当偏移量,会导致每次读取的位置都不对,比如第2个玩家你只偏移1字节,根本没定位到正确的结构体位置。

2. 循环里过早关闭文件流

你在第一次读取完一个玩家后就调用了readstream.close(),这直接把文件流关了!后面的循环根本读不到任何数据,playerTable里除了第一个元素,剩下的都是未初始化的垃圾值。

3. 写回文件时的覆盖问题

当你把playerTable写回文件时,因为数组里大部分是垃圾数据,再加上如果用了ios::out模式(默认会截断原文件),原文件里后续的有效结构体就被这些垃圾数据覆盖了,看起来就像是“消失”了。

修正后的完整代码

#include <fstream>
using namespace std;

struct player{
    int UUID;
};

// 更新玩家数据库中的玩家信息
bool savePlayer(player playerData){
    int count = 0;
    // 统计文件中的玩家数量
    fstream countstream("player.bin", ios::binary | ios::in);
    if(countstream.is_open()){
        countstream.seekg(0, ios::end);
        // 处理文件为空的情况,避免除以0
        if(countstream.tellg() != 0){
            count = countstream.tellg() / sizeof(player);
        }
        countstream.close();
    }

    bool found = false;
    player* playerTable = nullptr;

    // 读取现有玩家数据
    if(count > 0){
        // 用动态数组,避免栈溢出(玩家多了栈顶会爆)
        playerTable = new player[count];
        fstream readstream("player.bin", ios::binary | ios::in);
        if(readstream.is_open()){
            // 一次性读取所有数据,比循环读高效还不容易错
            readstream.read(reinterpret_cast<char*>(playerTable), count * sizeof(player));
            readstream.close();
        }

        // 查找并更新目标玩家
        for(int i = 0; i < count; i++){
            if(playerTable[i].UUID == playerData.UUID){
                found = true;
                playerTable[i] = playerData;
                break; // 找到就停,不用白跑循环
            }
        }
    }

    // 如果没找到,新增玩家
    if(!found){
        player* newTable = new player[count + 1];
        // 复制原有数据
        if(count > 0){
            for(int i = 0; i < count; i++){
                newTable[i] = playerTable[i];
            }
            delete[] playerTable;
        }
        newTable[count] = playerData;
        playerTable = newTable;
        count++;
    }

    // 把完整数据写回文件
    fstream writestream("player.bin", ios::binary | ios::out | ios::trunc);
    if(writestream.is_open()){
        writestream.write(reinterpret_cast<char*>(playerTable), count * sizeof(player));
        writestream.close();
    }

    // 记得释放动态内存,别内存泄漏
    delete[] playerTable;
    return true;
}

关键优化点说明

  • 改用一次性读取所有数据,避免手动计算偏移量的错误,代码也更简洁高效。
  • 把文件流的关闭移到循环外面,确保所有数据都读完再关流。
  • 动态数组替代栈数组,栈的空间有限,玩家多了会直接栈溢出崩溃。
  • 补充了新增玩家的逻辑,原代码只处理了更新的情况。
  • 明确用ios::trunc截断原文件后写入完整数据,保证文件内容和内存中的数组完全一致。

内容的提问来源于stack exchange,提问作者SpeedrunnerG55

火山引擎 最新活动