C++98下使用fwrite写入FILE文件失败,如何解决?
解决C++98中fwrite无法写入配置文件的问题
问题背景
使用C++98在NetBeans 8.0开发,已实现从simple.conf加载键值对数据到表单,但Update函数无法将表单中的字符串、IP地址、浮点数、整数写入该文件,配置文件格式为每行值 键。
核心错误分析
- 文件打开模式错误:Update函数用
"r"只读模式打开文件,无写入权限,根本无法修改文件内容。 - fwrite参数误用:
fwrite正确参数为fwrite(数据指针, 单个元素大小, 元素个数, 文件流),你写成了fwrite(name, sizeof(name), sizeof(name), fptr),会把整个50字节的char数组(含末尾垃圾数据)重复写入50次,完全不符合需求。 - 逻辑匹配错误:
- 匹配
Name时错误写入section数据 - 匹配
Section时错误写入class1数据 - 匹配
Number和Total时写入未初始化的grade数组(垃圾数据)
- 匹配
- 直接修改原文件风险:即使改成读写模式,原文件每行长度不同时,新内容会覆盖后续字节,导致文件结构混乱。
修正方案(安全读写版本)
采用「读取原文件内容→内存中修改→写入临时文件→替换原文件」的方式,避免直接修改原文件的风险,同时修正所有逻辑错误:
修正后的Update函数代码
#include "newForm.h" #include <stdio.h> #include <string.h> #include <errno.h> // 定义键值对结构 typedef struct { char value[50]; char key[50]; } ConfigPair; void newForm::Update() { // 1. 读取原配置文件所有内容到内存 FILE* fptr = fopen("/root/Desktop/simple.conf", "r"); if (!fptr) { perror("Failed to open config file for reading"); return; } ConfigPair pairs[10]; // 假设最多10个配置项 int pairCount = 0; while (pairCount < 10) { if (fscanf(fptr, "%s %s", pairs[pairCount].value, pairs[pairCount].key) != 2) { break; } pairCount++; } fclose(fptr); // 2. 用表单数据更新内存中的键值对 const char* name = widget.lineEdit_1->text().toLocal8Bit().constData(); const char* classVal = widget.lineEdit_2->text().toLocal8Bit().constData(); const char* section = widget.lineEdit_3->text().toLocal8Bit().constData(); const char* number = widget.lineEdit_4->text().toLocal8Bit().constData(); const char* total = widget.lineEdit_5->text().toLocal8Bit().constData(); for (int i = 0; i < pairCount; i++) { if (strcmp(pairs[i].key, "Name") == 0) { strncpy(pairs[i].value, name, sizeof(pairs[i].value)-1); pairs[i].value[sizeof(pairs[i].value)-1] = '\0'; // 确保字符串终止 } else if (strcmp(pairs[i].key, "Class") == 0) { strncpy(pairs[i].value, classVal, sizeof(pairs[i].value)-1); pairs[i].value[sizeof(pairs[i].value)-1] = '\0'; } else if (strcmp(pairs[i].key, "Section") == 0) { strncpy(pairs[i].value, section, sizeof(pairs[i].value)-1); pairs[i].value[sizeof(pairs[i].value)-1] = '\0'; } else if (strcmp(pairs[i].key, "Number") == 0) { strncpy(pairs[i].value, number, sizeof(pairs[i].value)-1); pairs[i].value[sizeof(pairs[i].value)-1] = '\0'; } else if (strcmp(pairs[i].key, "Total") == 0) { strncpy(pairs[i].value, total, sizeof(pairs[i].value)-1); pairs[i].value[sizeof(pairs[i].value)-1] = '\0'; } } // 3. 写入临时文件 FILE* tempFptr = fopen("/root/Desktop/simple.tmp", "w"); if (!tempFptr) { perror("Failed to open temp file for writing"); return; } for (int i = 0; i < pairCount; i++) { fprintf(tempFptr, "%s\t%s\n", pairs[i].value, pairs[i].key); } fclose(tempFptr); // 4. 替换原文件 if (remove("/root/Desktop/simple.conf") != 0) { perror("Failed to remove old config file"); remove("/root/Desktop/simple.tmp"); // 清理临时文件 return; } if (rename("/root/Desktop/simple.tmp", "/root/Desktop/simple.conf") != 0) { perror("Failed to rename temp file to config file"); remove("/root/Desktop/simple.tmp"); return; } }
关键修正点说明
- 文件操作逻辑:先只读读取原文件,再写入临时文件,最后替换原文件,避免直接修改原文件导致的数据损坏。
- 字符串安全处理:用
strncpy替代strcpy,避免缓冲区溢出,手动添加字符串终止符保证数据有效性。 - 匹配逻辑修正:每个键对应正确的表单输入数据,解决原代码中的匹配错误。
- 文本写入优化:用
fprintf替代fwrite,更适合文本格式配置文件,自动处理字符串长度,避免写入垃圾数据。
内容的提问来源于stack exchange,提问作者gatcheca
相关产品推荐
相关产品推荐

