获取文件大小
- 通过文件指针获取文件大小
- 通过文件描述符获取文件大小
因为音视频开发的需要,经常会写一些文件输入输出的测试程序,常常用到获取文件大小的函数。本篇文章就记录一下我常用的两种获取文件大小的方式。
通过文件指针获取文件大小
文件指针 就是调用 fopen() 函数返回的指向FILE结构体的指针,通过文件指针可以对文件进行打开、关闭、读写以及控制读写位置等操作。fopen() 就不做介绍了,这里主要说明用到的另外两个函数。
首先是 fseek(),用来移动文件指针,fseek的用法:
int fseek(FILE *stream, long offset, int whence);
/*
函数作用:以whence为基点,设置stream的文件指针到偏移offset的位置
参数说明:
stream 文件指针
offset 相对于whence的偏移值
whence 基准位置,可设置为
SEEK_SET (0) 文件头
SEEK_CUR (1) 当前位置
SEEK_END (2) 文件尾
返回值:设置成功返回0;设置失败返回-1,并设置errno的值。
*/
另一个就是ftell(),这个函数可以获取文件指针当前位置相对于文件头的偏移,当文件指针指向文件末尾时,ftell() 返回的就是文件的大小。ftell() 函数的用法:
long ftell(FILE *stream);
/*
函数作用:获取文件指针相对于文件头的偏移值。
参数说明:
stream 文件指针
返回值:获取成功返回当前偏移值;获取失败返回-1,并设置errno的值。
*/
通过文件指针获取文件大小的思路,就是使用fseek将文件指针移动到文件末尾,然后使用ftell获取文件指针相对于文件头的偏移即可得到文件的大小。有一点需要注意,为了不影响对文件的后续操作,需要记录文件指针的初始位置,并在函数退出前将文件指针恢复到初始位置。封装为函数如下:
long get_file_size(FILE *stream)
{
long file_size = -1;
long cur_offset = ftell(stream); // 获取当前偏移位置
if (cur_offset == -1) {
printf("ftell failed :%s\n", strerror(errno));
return -1;
}
if (fseek(stream, 0, SEEK_END) != 0) { // 移动文件指针到文件末尾
printf("fseek failed: %s\n", strerror(errno));
return -1;
}
file_size = ftell(stream); // 获取此时偏移值,即文件大小
if (file_size == -1) {
printf("ftell failed :%s\n", strerror(errno));
}
if (fseek(stream, cur_offset, SEEK_SET) != 0) { // 将文件指针恢复初始位置
printf("fseek failed: %s\n", strerror(errno));
return -1;
}
return file_size;
}
通过文件描述符获取文件大小
文件描述符即打开(open)或创建(creat)文件时内核向进程返回的非负整数,内核通过文件描述符访问文件。通过文件描述符获取文件大小只需要一个函数 fstat, fstat可以获取文件的状态,其中就包含文件大小的字段。
对于一个现有文件,一般使用 open() 获取其文件描述符。
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
/*
函数作用:打开一个文件。
参数说明:
pathname 文件路径及文件名
flag 打开标志,具体参考 open 函数的man-page
mode 打开模式,具体参考 open 函数的man-page
返回值:打开成功返回文件描述符;打开失败返回-1,并设置errno的值。
*/
接下来说明 stat 结构体和 fstat() 函数的用法:
struct stat {
dev_t st_dev; // 文件所在设备ID
ino_t st_ino; // 结点(inode)编号
mode_t st_mode; // 保护模式
nlink_t st_nlink; // 硬链接个数
uid_t st_uid; // 所有者用户ID
gid_t st_gid; // 所有者组ID
dev_t st_rdev; // 设备ID(如果是特殊文件)
off_t st_size; // 总体尺寸,以字节为单位
blksize_t st_blksize; // 文件系统 I/O 块大小
blkcnt_t st_blocks; // 已分配 512B 块个数
time_t st_atime; // 上次访问时间
time_t st_mtime; // 上次更新时间
time_t st_ctime; // 上次状态更改时间
};
int fstat(int fd, struct stat *statbuf);
/*
函数作用:获取文件状态。
参数说明:
fd 文件描述符
statbuf 指向文件状态结构体指针
返回值:获取成功返回0;获取失败返回-1,并设置errno的值。
*/
第一段代码中将文件指针作为了函数的参数,用于文件已使用 fopen() 打开的情况。下面的代码将文件名做为参数,用于文件未被打开的场景。
// 需要的头文件
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
off_t get_file_size(char *file_name)
{
int ret;
int fd = -1;
struct stat file_stat;
fd = open(file_name, O_RDONLY); // 打开文件
if (fd == -1) {
printf("Open file %s failed : %s\n", file_name, strerror(errno));
return -1;
}
ret = fstat(fd, &file_stat); // 获取文件状态
if (ret == -1) {
printf("Get file %s stat failed:%s\n", file_name, strerror(errno));
close(fd);
return -1;
}
close(fd);
return file_stat.st_size;
}
本文主要描述了通过文件指针和文件描述符获取文件大小的两种方式,并且提供了两个参考函数,可以在日常工作中根据需求使用。