最近做一个项目,需要获取文件大小,而文件大小又是超过 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;
}
楼主,为啥我在ubuntu下面获取的的printf("sizeof(off_t): %d\n", sizeof(off_t));是8
可以翻一翻相应的标准定义,不少数据类型的位宽都是未定义的,也就是说在不同的平台或者系统中,它们的表现可能不一致。
类unix系统下,64位处理器的long是8,windows是4