Unity3D热门教程

游戏开发工具

C语言是一种比较底层的语言,有时在其他语言中很容易操作的事情,在C语言中就比较麻烦,例如获取一个文件的大小。Java中File类有个length函数,Python中os.path包中有个getsize函数,C语言中却没有直接对应的函数获取文件大小。

C语言获取文件大小(长度)

实际开发中,有时候需要先获取文件大小再进行下一步操作。C语言没有提供获取文件大小的函数,要想实现该功能,必须自己编写函数。

fseek函数

语法:

#include <stdio.h>
int fseek( FILE *stream, long offset, int origin );

函数fseek()为给出的流设置位置数据. origin的值应该是下列值其中之一(在stdio.h中定义):

名称说明
SEEK_SET从文件的开始处开始搜索
SEEK_CUR从当前位置开始搜索
SEEK_END从文件的结束处开始搜索

fseek()成功时返回0,失败时返回非零. 你可以使用fseek()移动超过一个文件,但是不能在开始处之前. 使用fseek()清除关联到流的EOF标记.

ftell()函数

语法:

#include <stdio.h>
long ftell( FILE *stream );

ftell() 函数用来获取文件内部指针(位置指针)距离文件开头的字节数,它的原型为:

long int ftell ( FILE * fp );

注意:fp 要以二进制方式打开,如果以文本方式打开,函数的返回值可能没有意义。


先使用 fseek() 将文件内部指针定位到文件末尾,再使用 ftell() 返回内部指针距离文件开头的字节数,这个返回值就等于文件的大小。

请看下面的代码:

long fsize(FILE *fp)
{
    fseek(fp, 0, SEEK_END);
    return ftell(fp);
}

这段代码并不健壮,它移动了文件内部指针,可能会导致接下来的文件操作错误。

例如:

long size = fsize(fp);
fread(buffer, 1, 1, fp);

fread() 函数将永远读取不到内容。

所以,获取到文件大小后还需要恢复文件内部指针,请看下面的代码:

long fsize(FILE *fp)
{
    long n;
    fpos_t fpos; //当前位置
    fgetpos(fp, &fpos); //获取当前位置
    fseek(fp, 0, SEEK_END);
    n = ftell(fp);
    fsetpos(fp,&fpos); //恢复之前的位置
    return n;
}

fpos_t 是在 stdio.h 中定义的结构体,用来保存文件的内部指针。

fgetpos() 用来获取文件内部指针,

fsetpos() 用来设置文件内部指针。

上述方法利用fseek移动一个文件的存取位置到文件的末尾,然后利用ftell获得目前的文件访问位置。这种方法可以认为是一种间接的获取方式。虽说可以获得文件大小,但是有两个缺点。首先,ftell的返回值为long,在不同环境下占用的字节数也不同,这就可能存在long是四个字节的情况。此时,获取的文件大小就不能超过2G,否则就会出错。


但是,上述缺点在大多数情况下都没问题,超大文件还可以通过fsetpos和fgetpos获取文件大小。最致命的缺陷就是它需要加载文件到内存,然后跳转到文件末尾,这个操作非常耗时!可能在读取少量文件时体现不出,但是当文件达到上万个时,速度就会慢的要命,这种方法相当于把所有的文件都读到内存中一遍!


如果可能,尽量避免采用上述间接的方式获取文件大小。在linux下,还有一种更简单的方式,通过读取文件信息获得文件大小,速度也快很多。

完整的示例:

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
long fsize(FILE *fp);
int main()
{
    long size = 0;
    FILE *fp = NULL;
    char filename[30] = "D:\\1.mp4";
    if( (fp = fopen(filename, "rb")) == NULL ){ //以二进制方式打开文件
        printf("Failed to open %s...", filename);
        getch();
        exit(EXIT_SUCCESS);
    }
    printf("%ld\n", fsize(fp));
    return 0;
}
long fsize(FILE *fp)
{
    long n;
    fpos_t fpos; //当前位置
    fgetpos(fp, &fpos); //获取当前位置
    fseek(fp, 0, SEEK_END);
    n = ftell(fp);
    fsetpos(fp,&fpos); //恢复之前的位置
    return n;
}

这种方式首先获得相关文件的状态信息,然后从状态信息中读取大小信息。由于没有读取文件的操作,所以操作速度非常快。强烈建议大家在linux下使用这种方式。Windows平台下肯定也有类似的函数读取文件信息,不过本人常年不在windows下编程,所以在此不做介绍。