fread读取二进制文件抛出异常,已确认fileSize正确,求修正方案
问题分析与修复方案
你的readFile函数在调用fread时出现崩溃(你描述的“抛出异常”在C中通常指段错误或信号触发的程序终止),结合你提到fileSize能正确获取文件字节数,以下是问题原因和修复步骤:
可能的核心原因
- 错误判断不精准:
fread返回字节数小于fileSize时,可能是读取过程中发生了权限问题、文件被锁定等错误,而非单纯到达文件末尾,原代码未区分这两种情况。 fseek+ftell的兼容性局限:对于部分特殊文件(如管道、设备文件),fseek(SEEK_END)的行为未定义,虽然你确认fileSize正确,但这种方式本身存在隐性风险。- 内存分配的隐性问题:部分系统开启内存过度提交后,
malloc可能返回非空指针但实际内存不足,导致fread写入时触发内存错误。
修复后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/stat.h> static char* readFile(const char* path) { FILE* file = fopen(path, "rb"); if (!file) { fprintf(stderr, "无法打开文件 \"%s\":%s\n", path, strerror(errno)); exit(1); } // 用fstat替代fseek+ftell,更可靠获取文件大小 struct stat st; if (fstat(fileno(file), &st) == -1) { fprintf(stderr, "获取文件大小失败 \"%s\":%s\n", path, strerror(errno)); fclose(file); exit(1); } size_t fileSize = st.st_size; char* buffer = malloc(fileSize + 1); // sizeof(char)恒为1,可省略 if (!buffer) { fprintf(stderr, "内存不足,无法读取文件 \"%s\"\n", path); fclose(file); exit(1); } size_t bytesRead = fread(buffer, 1, fileSize, file); // 区分读取错误与文件提前结束 if (bytesRead < fileSize) { if (ferror(file)) { fprintf(stderr, "读取文件 \"%s\" 出错:%s\n", path, strerror(errno)); } else { fprintf(stderr, "文件 \"%s\" 提前结束,未读取完整\n", path); } free(buffer); fclose(file); exit(1); } buffer[bytesRead] = '\0'; fclose(file); return buffer; }
关键修复点
- 替换文件大小获取方式:
fstat通过文件描述符直接读取系统元数据,避免了fseek对特殊文件的兼容性问题,结果更可靠。 - 细化错误处理:用
ferror(file)区分读取错误和文件提前结束的场景,结合strerror(errno)输出具体错误信息,方便定位问题。 - 避免内存泄漏:读取失败时及时释放已分配的内存,再关闭文件退出。
- 简化代码:省略冗余的
sizeof(char),因为C标准定义其值恒为1。
额外排查建议
- 确认目标文件的读取权限,确保当前进程有权限访问该文件。
- 若处理超大文件(超过
long类型范围),ftell会返回错误,但stat的st_size在64位系统中支持更大的文件尺寸。 - 检查系统内存配置,若存在内存过度提交导致的虚假分配问题,可调整系统参数或增加可用内存。
内容的提问来源于stack exchange,提问作者Borges
相关产品推荐
相关产品推荐

