如何在不使用fseek或stat的情况下在C中获取文件的大小?

Use*_*ess 0 c size file

我正在为我的学校做一个项目,我无法找到如何获得文件的大小.因为我需要读取一个脚本并在我的程序中使用它,所以我需要使用read或fread这个文件的大小.

这是我为获取文件大小所做的,但它似乎不起作用.

int my_size(int filedesc)
{
    int size = 1;
    int read_output = 1;
    char *buffer;

    for (size = 1; read_output != 0 ; size++) {
        buffer = malloc((size+1)*sizeof(char*));
        read_output = read(filedesc, buffer, size);
        free(buffer);
    }
    return(size);
}
Run Code Online (Sandbox Code Playgroud)

并且我不允许使用stat()和fseek()作为此项目的规则,也不允许使用任意大小(如100)的read或fread,因为给出的脚本可能很小或很大.

Joh*_*ger 7

如果您可以依赖输入作为持久文件(即驻留在存储介质上),并且在程序运行期间没有修改该文件,那么您可以预先读取它以计算其中的字节数,然后倒带.

但是在学术练习之外,禁止通过stat(),fseek()类似地测量大小的通常原因是输入可能不会驻留在存储介质上,因此

  1. 如果不阅读它,你就无法确定它的大小
  2. 你无法倒回或在其中寻找.

那么诀窍不是如何提前确定尺寸,而是如何在预先测量尺寸的情况下确定尺寸.至少有两个主要策略:

  • 首先不要依赖于将整个内容存储在内存中.相反,在读取内容时对其内容进行操作,在任何给定时间仅在内存中保持足够的内容.

  • 或者,动态调整文件大小.这有很多变化.例如,如果您只是将文件读入整体块中,那么您可以malloc()放置空间,realloc()当您发现需要更多时.或者您可以将内容存储在链接列表中,根据需要分配新的列表节点.

至于问题中提出的方法,它有几个问题.它似乎是我第一次描述的尝试 - 将文件读到最后以确定其大小 - 但是

  1. 它似乎假设每个read()都将从文件的开头开始,或者read()如果它无法读取整个文件,那么它可能会失败.情况也不是这样.每个read()都将从文件的当前位置开始,并将文件保留在传输的最后一个字节之后.

  2. 因为它会改变文件位置,所以你的方法将要求文件在之后重绕 - lseek()例如.但是,如果lseek()可以用于此目的(并且请注意我之前关于您无法搜索的文件的评论),那么它将提供一种更清晰的方法来测量文件的大小.

  3. 您没有考虑I/O错误.如果发生一个,那么它可能会将您的程序发送到无限循环.

  4. 动态分配比较昂贵,而且你做了很多.如果您想实施预读策略,那么这将是一个更好的实现:

    ssize_t count_bytes(int fd) {
        ssize_t num_bytes = 0;
        char buffer[2048];
        ssize_t result;
    
        do {
            result = read(fd, buffer, sizeof(buffer));
            if (result < 0) {
                // handle error ...
            }
            num_bytes += result;
        while (result > 0);
    
        return num_bytes;
    }
    
    Run Code Online (Sandbox Code Playgroud)

  • @Useless,在这种情况下,练习的限制似乎旨在强迫你采用我描述的第一个策略:"不要依赖于首先将所有内容一次存储在内存中." 我特别倾向于这样认为,如果"链接列表不够熟练"可以扩展为"不希望*链接列表足够熟练[...]". (2认同)