You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:53:58