如何移动std::ofstream写入指针 实现修改文件中间内容而不重写全文件
解决方案说明
首先说明:如果你的分数文件体积很小(只有几十上百条玩家记录),全读全改全写的性能损耗几乎可以忽略,实现起来反而更简单不容易出错。如果是大文件场景或者对性能有强要求,可以用下面的方案:
1. 你要的定位写入方法确实存在
C++标准库的文件输出流提供了seekp()方法,作用就是设置写入指针的位置,和你提到的setpos功能完全一致。
注意:该方法仅适用于修改前后内容字节长度完全相同的场景,否则新内容会覆盖后续的原有数据。你的当前场景刚好符合要求:原分数
10和修改后的50都是2位字符,整行长度无变化,可直接用该方法修改。
2. 具体实现步骤
- 首先打开文件时指定
std::ios::in | std::ios::out模式,禁止使用默认的std::ios::trunc截断模式,避免打开时清空原有内容 - 遍历文件逐行匹配
player2的记录,同时记录下分数字段对应的字节偏移量 - 调用
seekp()定位到分数偏移位置,直接写入新的分数即可
3. 代码示例
#include <fstream> #include <string> #include <iostream> int main() { std::fstream score_file("scores.txt", std::ios::in | std::ios::out); if (!score_file.is_open()) { std::cerr << "文件打开失败" << std::endl; return 1; } std::string line; std::streampos score_pos = -1; // 逐行查找player2的记录 while (std::getline(score_file, line)) { // C++20之前的标准可替换为 line.substr(0, 8) == "player2:" if (line.starts_with("player2:")) { // 计算分数的偏移位置:当前读指针位置 减去 该行长度 再加上 "player2: "的长度(9个字符) score_pos = score_file.tellg() - (std::streampos)line.size() + 9; break; } } if (score_pos != -1) { // 定位到写入位置 score_file.seekp(score_pos); // 写入新分数,刚好2位覆盖原有内容 score_file << "50"; } score_file.close(); return 0; }
4. 其他场景优化建议
- 如果后续会频繁修改玩家分数,建议预先为每个玩家的分数预留固定长度的存储空间,或者直接建立偏移索引表,不需要每次修改都遍历文件,性能提升非常明显
- 如果修改后的内容长度和原有长度不一致,没有办法完全避免读写后续内容:可以只读取修改位置之后的内容,写完修改内容后再把后续内容追加回去,相比全文件读写性能更好
- 如果业务逻辑比较复杂,更推荐直接使用SQLite等轻量嵌入式数据库,底层的增删改查都已经做好优化,不需要自己处理文件操作的各种边界问题
内容的提问来源于stack exchange,提问作者silver takana
相关产品推荐
相关产品推荐

