linux下c语言编程,获取超大文件大小(size超过2GB)

最近做一个项目,需要获取文件大小,而文件大小又是超过 2GB 的。这就导致很多 c 标准函数不能正常工作。

linux c语言获取文件大小常用方法


常用方法有两类:

  • 利用 seek 系函数。
    以 lseek 函数为例,它可以将定位要读写文件的位置,正常情况下,它会返回当前读写指针位置。让其指向文件末尾,即可获得文件大小。

  • 利用 stat 系函数。
    推荐用这个函数,比较简单,是专用来获取文件信息的函数。

seek 系函数获取文件大小

直接上代码:

int get_file_size(char* filename) 
{ 
  int fd = open(filename, O_RDWR, 0666); 
  if(fd<0) 
      return 0; 
  off_t size = lseek(fd,0,SEEK_END); 
  close(fp); 

  return size; 
} 

stat 系函数获取文件大小

off_t get_file_size(char* filename) 
{ 
  struct stat sstat; 
  stat(filename, &sstat); 
  off_t size=sstat.st_size; 

  return size; 
}

为何seek函数stat函数不能获取大于2GB的超大文件大小


以上介绍的两个例子在获取小于 2GB 的文件大小时,可以很好的工作,但是当文件大小大于 2GB 时,就不正常了。

其实,这主要是数据类型的长度限制的。lseek 的函数原型如下:

off_t lseek(int fildes,off_t offset ,int whence);

struct stat 的原型如下:

struct stat {
        mode_t     st_mode;       //文件对应的模式,文件,目录等
        ino_t      st_ino;       //inode节点号
        dev_t      st_dev;        //设备号码
        dev_t      st_rdev;       //特殊设备号码
        nlink_t    st_nlink;      //文件的连接数
        uid_t      st_uid;        //文件所有者
        gid_t      st_gid;        //文件所有者对应的组
        off_t      st_size;       //普通文件,对应的文件字节数*****
        time_t     st_atime;      //文件最后被访问的时间
        time_t     st_mtime;      //文件内容最后被修改的时间
        time_t     st_ctime;      //文件状态改变时间
        blksize_t  st_blksize;    //文件内容对应的块大小
        blkcnt_t   st_blocks;     //文件内容对应的块数量
      };

会发现,咱们要返回的值类型都是 off_t 的。
执行以下代码:

printf("sizeof(off_t): %d\n", sizeof(off_t));

输出如果是 4,就很好理解为何以上函数只能获取小于 2GB 的文件大小了。

linux C语言获取大于2GB的超大文件大小


在/usr/include中执行shell命令:

grep __USE_FILE_OFFSET64 /usr/include/* -r

查找 off_t类型的定义可以看出,off_t其实拥有两种类型:__off_t和__off64_t

要使 off_t为__off64_t类型,必须

#define __USE_FILE_OFFSET64.

还找到了这个:

#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
# define __USE_FILE_OFFSET64    1
#endif

所以,我们在包含所有头文件之前,需要:

#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif

#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif

这样就可以64位偏移地址形式操作文件。

咱们以 stat 函数为例,使用其 64 位类型的函数,代码如下:

#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif

#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>


off_t get_file_size(const char *filename)  
{  
    struct stat64 buf;  
    if(stat64(filename, &buf)<0)  
    {
        printf("cannot open file\n");
        return 0;  
    } 
    printf("st_size: %lld\n", (off_t)buf.st_size);
    return (off_t)buf.st_size;  
}

应该很容易看懂,这样,咱们就完成了 linux 下C语言获取大于2GB的超大文件大小的代码了。

阅读更多:   Linux笔记
已有 2 条评论
  1. lwei2

    楼主,为啥我在ubuntu下面获取的的printf("sizeof(off_t): %d\n", sizeof(off_t));是8

    1. 可以翻一翻相应的标准定义,不少数据类型的位宽都是未定义的,也就是说在不同的平台或者系统中,它们的表现可能不一致。

添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif