You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二进制文件读写技术求助:实现写入、定位读取与数据覆盖

问题与解决方案

原始代码

#include <iostream>
#include <fstream>
#include <cstring>

struct Data {
  char *Hold1;
  char *Hold2;
};

int main() {
  
//Variables
  int choice , loop = 0, RecAmount = 0;
  std::string DepName, output1;
  double inp2, output2;

////File Check
   std::fstream inventory;
    inventory.open("inventory.dat", std::ios::out|std::ios::in|std::binary );
    if (inventory.fail()){
      inventory.open("inventory.dat", std::ios::out|std::ios::in | std::binary|           
      std::ios::trunc);
      std::cout << "Error opening file....";
        return 0; }

  while (loop < 1) {
    std::cout << "
Read/write testing
";
    std::cout << "1. Input Data
";
    std::cout << "2. Read Data Output
";
    std::cin >> choice;

////Input 2 strings
    if (choice == 1) {
      std::cout << "Testing input
";

      struct Data test1;
      test1.Hold1 = "First test";
      test1.Hold2 = 29;

      
     
      }

    if (choice == 2) {
      std::cout << "Testing output
";
      
      //// Add way to choose which data is read and displayed
      inventory.read ((char *)& inp2, sizeof(Data));

      

      std::cout << "Character input = " << output1 << std::endl;
    }
  }
}

需求

  • 向名为inventory.dat的二进制文件写入数字和字符数组
  • 可定位并读取指定信息(如输入3组数据后仅显示第2组)
  • 可覆盖任意指定数据(如找到第2组数据并修改)

解决方案

1. 修正结构体定义

原始结构体用char*指针存储数据,直接写入二进制文件只会保存内存地址,程序重启后地址失效。改成固定大小的字符数组+基础数字类型,确保二进制存储的一致性:

#include <iostream>
#include <fstream>
#include <cstring>

// 定义POD类型结构体,适合二进制存储
struct Data {
    char Hold1[50];  // 预留足够空间存储字符串(最多49字符)
    int Hold2;       // 用int存储数字,替代无效的char*
};

2. 写入数据到二进制文件

使用fstream::write方法追加数据到文件末尾,每次写入一个完整的Data结构体:

// 写入数据函数
void writeData(std::fstream& file, const Data& data) {
    file.seekp(0, std::ios::end); // 移动写指针到文件末尾
    file.write(reinterpret_cast<const char*>(&data), sizeof(Data));
}

在主菜单的写入数据分支调用:

if (choice == 1) {
    Data test1;
    std::cin.ignore(); // 清除输入缓冲区的换行符
    std::cout << "输入字符串(最多49字符):";
    std::cin.getline(test1.Hold1, 50);
    std::cout << "输入数字:";
    std::cin >> test1.Hold2;

    writeData(inventory, test1);
    std::cout << "数据写入成功!\n";
}

3. 读取指定位置的数据

二进制文件中每个Data结构体占sizeof(Data)字节,第N条数据的起始位置为(N-1)*sizeof(Data)。用seekg定位读指针后读取:

// 读取指定序号的数据(序号从1开始)
bool readData(std::fstream& file, int index, Data& outData) {
    // 计算文件总条目数
    file.seekg(0, std::ios::end);
    std::streampos totalBytes = file.tellg();
    int totalItems = totalBytes / sizeof(Data);

    if (index < 1 || index > totalItems) {
        std::cout << "无效的条目序号!\n";
        return false;
    }

    // 定位到目标条目起始位置
    std::streampos targetPos = (index - 1) * sizeof(Data);
    file.seekg(targetPos);
    file.read(reinterpret_cast<char*>(&outData), sizeof(Data));

    return true;
}

在主菜单的读取数据分支调用:

if (choice == 2) {
    int index;
    std::cout << "输入要读取的条目序号:";
    std::cin >> index;

    Data result;
    if (readData(inventory, index, result)) {
        std::cout << "\n第" << index << "条数据:\n";
        std::cout << "字符串:" << result.Hold1 << "\n";
        std::cout << "数字:" << result.Hold2 << "\n";
    }
}

4. 修改指定位置的数据

修改逻辑与读取类似,定位到目标位置后用write覆盖原有数据:

// 修改指定序号的数据
bool updateData(std::fstream& file, int index, const Data& newData) {
    file.seekg(0, std::ios::end);
    std::streampos totalBytes = file.tellg();
    int totalItems = totalBytes / sizeof(Data);

    if (index < 1 || index > totalItems) {
        std::cout << "无效的条目序号!\n";
        return false;
    }

    std::streampos targetPos = (index - 1) * sizeof(Data);
    file.seekp(targetPos); // 移动写指针到目标位置
    file.write(reinterpret_cast<const char*>(&newData), sizeof(Data));

    return true;
}

在主菜单中增加修改数据选项并调用:

std::cout << "3. 修改指定数据\n";
// ...
if (choice == 3) {
    int index;
    std::cout << "输入要修改的条目序号:";
    std::cin >> index;

    Data newData;
    std::cin.ignore();
    std::cout << "输入新字符串:";
    std::cin.getline(newData.Hold1, 50);
    std::cout << "输入新数字:";
    std::cin >> newData.Hold2;

    if (updateData(inventory, index, newData)) {
        std::cout << "数据修改成功!\n";
    }
}

完整修正后的代码

#include <iostream>
#include <fstream>
#include <cstring>

struct Data {
    char Hold1[50];
    int Hold2;
};

void writeData(std::fstream& file, const Data& data) {
    file.seekp(0, std::ios::end);
    file.write(reinterpret_cast<const char*>(&data), sizeof(Data));
}

bool readData(std::fstream& file, int index, Data& outData) {
    file.seekg(0, std::ios::end);
    std::streampos totalBytes = file.tellg();
    int totalItems = totalBytes / sizeof(Data);

    if (index < 1 || index > totalItems) {
        std::cout << "无效的条目序号!\n";
        return false;
    }

    std::streampos targetPos = (index - 1) * sizeof(Data);
    file.seekg(targetPos);
    file.read(reinterpret_cast<char*>(&outData), sizeof(Data));

    return true;
}

bool updateData(std::fstream& file, int index, const Data& newData) {
    file.seekg(0, std::ios::end);
    std::streampos totalBytes = file.tellg();
    int totalItems = totalBytes / sizeof(Data);

    if (index < 1 || index > totalItems) {
        std::cout << "无效的条目序号!\n";
        return false;
    }

    std::streampos targetPos = (index - 1) * sizeof(Data);
    file.seekp(targetPos);
    file.write(reinterpret_cast<const char*>(&newData), sizeof(Data));

    return true;
}

int main() {
    int choice;
    bool loop = true;

    std::fstream inventory;
    inventory.open("inventory.dat", std::ios::out | std::ios::in | std::binary);
    if (inventory.fail()) {
        // 文件不存在时创建新文件
        inventory.open("inventory.dat", std::ios::out | std::binary);
        inventory.close();
        inventory.open("inventory.dat", std::ios::out | std::ios::in | std::binary);
        if (inventory.fail()) {
            std::cout << "无法打开或创建文件!\n";
            return 0;
        }
    }

    while (loop) {
        std::cout << "\n===== 二进制文件操作菜单 =====\n";
        std::cout << "1. 写入数据\n";
        std::cout << "2. 读取指定数据\n";
        std::cout << "3. 修改指定数据\n";
        std::cout << "4. 退出\n";
        std::cout << "请输入选择:";
        std::cin >> choice;

        switch (choice) {
            case 1: {
                Data test1;
                std::cin.ignore();
                std::cout << "输入字符串(最多49字符):";
                std::cin.getline(test1.Hold1, 50);
                std::cout << "输入数字:";
                std::cin >> test1.Hold2;

                writeData(inventory, test1);
                std::cout << "数据写入成功!\n";
                break;
            }
            case 2: {
                int index;
                std::cout << "输入要读取的条目序号:";
                std::cin >> index;

                Data result;
                if (readData(inventory, index, result)) {
                    std::cout << "\n第" << index << "条数据:\n";
                    std::cout << "字符串:" << result.Hold1 << "\n";
                    std::cout << "数字:" << result.Hold2 << "\n";
                }
                break;
            }
            case 3: {
                int index;
                std::cout << "输入要修改的条目序号:";
                std::cin >> index;

                Data newData;
                std::cin.ignore();
                std::cout << "输入新字符串:";
                std::cin.getline(newData.Hold1, 50);
                std::cout << "输入新数字:";
                std::cin >> newData.Hold2;

                if (updateData(inventory, index, newData)) {
                    std::cout << "数据修改成功!\n";
                }
                break;
            }
            case 4: {
                loop = false;
                std::cout << "程序退出。\n";
                break;
            }
            default: {
                std::cout << "无效选择,请重新输入!\n";
                break;
            }
        }
    }

    inventory.close();
    return 0;
}

关键知识点说明

  • 二进制文件核心操作:用seekg(读指针)和seekp(写指针)定位文件位置,tellg获取当前指针位置以计算总条目数。
  • 结构体存储要求:必须使用POD类型(普通旧数据类型),不能包含指针或非POD成员(如std::string),否则二进制写入会丢失数据。若需使用std::string,需手动序列化字符串长度和内容。
  • 文件打开模式:std::ios::binary确保文件以二进制模式打开,避免系统自动转换换行符导致数据错位。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 19:25:26