C语言禁用fseek/stat时如何获取文件大小?项目代码故障求助
问题分析与解决方案
首先,咱们先看看你这段代码里的几个关键问题,这些问题导致它无法正确获取文件大小:
原代码的核心问题
- 内存分配错误:你用了
malloc((size+1)*sizeof(char*)),但实际上你需要分配的是能容纳size个字符的空间,应该写成malloc(size)(因为sizeof(char)固定为1,直接写size即可)。sizeof(char*)是指针的大小(比如64位系统是8字节),这会让你分配远大于需要的内存,完全没必要。 - 文件指针未重置:每次调用
read后,文件描述符的指针会移动到读取的末尾。等你循环完,指针已经在EOF位置了,后续如果要读取文件内容,根本读不到东西。 - 循环逻辑与计数错误:你的循环是每次递增
size然后读取对应字节数,这种方式不仅效率极低(频繁malloc/free),而且计数逻辑有问题——比如当文件剩余字节数小于当前size时,read会返回实际读取的字节数,但你的循环还是会让size自增,最后返回的数值会比实际文件大小大。 - 未处理错误情况:
read可能返回-1表示读取失败(比如权限问题、文件被意外关闭),你的代码没处理这种情况,会导致死循环。
正确的实现方案
根据你的项目限制(不能用 stat()/fseek(),不能用固定大小一次性读整个文件),这里给你两种可行的方案:
方案1:用块读取累计大小 + 恢复文件指针
这个方案用固定大小的块(比如1024字节)循环读取文件,累计总字节数,同时保存并恢复文件指针位置,不影响后续读取操作。这里用1024是合理的块大小,不是用来一次性读整个文件,符合你的规则:
#include <unistd.h> #include <stdlib.h> int my_size(int filedesc) { // 先保存当前文件指针的位置,方便后续恢复 off_t original_pos = lseek(filedesc, 0, SEEK_CUR); if (original_pos == -1) { return -1; // 获取指针位置失败,返回错误码 } int total_size = 0; char buffer[1024]; // 栈上的缓冲区,避免频繁malloc/free ssize_t bytes_read; // 循环读取直到EOF或出错 while ((bytes_read = read(filedesc, buffer, sizeof(buffer))) > 0) { total_size += bytes_read; } // 检查读取是否出错 if (bytes_read == -1) { // 出错了,先恢复指针位置再返回错误 lseek(filedesc, original_pos, SEEK_SET); return -1; } // 恢复文件指针到最初的位置,方便后续读取文件内容 if (lseek(filedesc, original_pos, SEEK_SET) == -1) { return -1; } return total_size; }
方案2:直接读取整个文件到内存(无需lseek)
如果你的项目连 lseek 都禁止使用,那可以直接把文件内容读到动态分配的内存里,同时返回总大小。这样后续你就可以直接用这块内存,不需要再调用 read 了:
#include <unistd.h> #include <stdlib.h> // 返回文件大小,同时把文件内容存入out_buffer(需要手动free) int my_size_and_read(int filedesc, char **out_buffer) { *out_buffer = NULL; int total_size = 0; ssize_t bytes_read; const size_t chunk_size = 1024; // 初始化缓冲区 char *buffer = malloc(chunk_size); if (!buffer) { return -1; // 内存分配失败 } // 循环读取文件,动态扩展缓冲区 while ((bytes_read = read(filedesc, buffer + total_size, chunk_size)) > 0) { total_size += bytes_read; // 扩展缓冲区,预留chunk_size的空间避免频繁realloc char *temp_buffer = realloc(buffer, total_size + chunk_size); if (!temp_buffer) { free(buffer); return -1; } buffer = temp_buffer; } // 检查读取错误 if (bytes_read == -1) { free(buffer); return -1; } // 可选:把缓冲区调整到实际大小,若需要存字符串可以加个终止符 char *final_buffer = realloc(buffer, total_size + 1); if (final_buffer) { buffer = final_buffer; buffer[total_size] = '\0'; // 如果需要处理文本文件的话 } *out_buffer = buffer; return total_size; }
使用提示
- 方案1适合你需要先获取大小再单独读取文件的场景,记得检查返回值是否为-1(表示出错)。
- 方案2更直接,一次性获取大小和内容,但要记得用完后调用
free()释放内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Useless
相关产品推荐
相关产品推荐

