fwrite()写入文件末尾出现垃圾数据,PostgreSQL执行SQL文件异常排查
问题分析与解决方案
核心问题:文本模式导致字节数不匹配
你用"r"(文本模式)打开输入文件,在Windows系统下,文件里的\r\n会被自动转换为\n,这使得fread实际读取的字节数比stat获取的st_size要少。此时dbschema数组中,从实际读取的字节位置到buf.st_size之间的内存是未初始化的垃圾数据,之后你用fwrite写入了buf.st_size+1字节(包含这些垃圾数据),直接导致输出文件多出大量无效内容。
其他潜在问题
- 未校验
fread的返回值,无法确认是否读取了预期的全部字节; - 未判断输出文件
tbout.sql的打开结果,如果打开失败,后续的写操作都会出错; - 未校验
stat函数的返回值,若获取文件信息失败,后续逻辑全是错误的。
修正后的代码
struct stat buf; if (stat("treebase.sql", &buf) != 0) { wxMessageBox(_("Failed to get file info")); return; } char* dbschema = new (std::nothrow) char[buf.st_size + 1]; if (!dbschema) { wxMessageBox(_("Not Enough memory")); return; } FILE* fl = fopen("treebase.sql", "rb"); // 用二进制模式打开,避免换行转换 if (!fl) { wxMessageBox(_("Can not open treebase.sql")); delete[] dbschema; return; } FILE* fo = fopen("tbout.sql", "wb"); // 二进制模式写入,保证字节一致 if (!fo) { wxMessageBox(_("Can not open tbout.sql")); fclose(fl); delete[] dbschema; return; } size_t read_bytes = fread(dbschema, sizeof(char), buf.st_size, fl); fclose(fl); // 验证是否读取了完整文件 if (read_bytes != buf.st_size) { wxMessageBox(_("Failed to read entire file")); fclose(fo); delete[] dbschema; return; } dbschema[buf.st_size] = '\0'; // 只写入文件实际大小的内容,不需要额外多写一个字节 fwrite(dbschema, sizeof(char), buf.st_size, fo); fflush(fo); fclose(fo); delete[] dbschema;
关键修正点
- 改用二进制模式
"rb"和"wb"打开文件,彻底避免换行符转换带来的字节数偏差; - 增加所有关键IO函数的返回值校验,提前拦截异常情况;
- 写入文件时只写原文件大小的内容,不再包含未初始化的垃圾数据。
内容的提问来源于stack exchange,提问作者San Pei
相关产品推荐
相关产品推荐

