用来获取文件的详细状态信息。它可以用来检索与文件相关的属性,如文件的权限、所有者、大小、时间戳等信息。
1.头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
2.函数原型
int stat(const char *pathname, struct stat *statbuf);
3.参数
pathname:输入参数,指需要获取状态信息的文件或者目录的路径名字
stabuf:输出参数,用来存储获取到的文件状态信息的结构体指针
4.返回值
成功:返回值为0,并且在struct stat结构体中被填充为指定的文件或者目录的详细状态信息。
失败:返回值为-1,并且在errno变量返回错误的原因,如文件不存在、权限不足或者无效的路径等。
struct stat结构体介绍:
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 块数 */
/* 自 Linux 2.6 起,以下时间戳字段支持纳秒精度 */
struct timespec st_atim; /* 最后访问时间 */
struct timespec st_mtim; /* 最后修改时间 */
struct timespec st_ctim; /* 最后状态改变时间 */
/* 以下宏定义用于向后兼容早期版本 */
#define st_atime st_atim.tv_sec /* 最后访问时间,秒部分 */
#define st_mtime st_mtim.tv_sec /* 最后修改时间,秒部分 */
#define st_ctime st_ctim.tv_sec /* 最后状态改变时间,秒部分 */
};
struct stat结构体是在<sysy/stat.h>头文件中定义的,其中包含了文件的各种状态信息,
上面的结构体定义基本定义已经在注释中介绍完了,
需要注意的是结构体在struct timespec结构体部分,是在Linux2.6内核之后才支持的结构体定义,在旧版本的内核中并使用的是time_t类型的结构体来储存的时间(秒),这样的操作是为了确保新版本与旧版的内核做到兼容,使用时可以直接使用st_atime、st_mtime、st_ctime宏定义来获取文件的各个时间状态。
1)st_mode字段
st_mode字段本质上是一个32位无符号整形数据,该变量主要记录了文件的类型、文件的权限信息,虽然st_mode是一个32位的无符号整形数据,但实际只用到了低16位,下面就是低16位所代表的含义。
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| 文件类型 | 文件特殊权限(S) | 文件所有者权限(U) | 同组用户权限(G) | 其他用户权限(O) | |||||||||||
文件类型为4bit,对应的为15-12位,用来描述是普通文件、链接文件、目录等文件状态。剩下的11-0位分别对应文件的特殊权限(S)、文件所有者权限(U),同组用户权限(G)、其他用户权限(O)。
2)文件类型宏定义
S_IFMT 0170000 文件类型字段掩码位
S_IFSOCK 0140000 socket(套接字文件)
S_IFLNK 0120000 symbolic link(链接文件)
S_IFREG 0100000 regular file(普通文件)
S_IFBLK 0060000 block device(块设备文件)
S_IFDIR 0040000 directory(目录)
S_IFCHR 0020000 character device(字符设备文件)
S_IFIFO 0010000 FIFO(管道文件)
3)文件特殊权限(S)
S_ISUID 04000 /* Set user ID on execution. */
S_ISGID 02000 /* Set group ID on execution. */
S_ISVTX 01000 /* Save swapped text after use (sticky). */
4)文件所有者权限(U)的宏定义
S_IRUSR 00400 /* Read by owner. */
S_IWUSR 00200 /* Write by owner. */
S_IXUSR 00100 /* Execute by owner. */
S_IRWXU 00700 /* Read, write, and execute by owner. */
5)同组用户权限(G)宏定义
S_IRGRP 00040 /* Read by group. */
S_IWGRP 00020 /* Write by group. */
S_IXGRP 00010 /* Execute by group. */
S_IRWXG 00070 /* Read, write, and execute by group. */
6)其他用户权限(O)宏定义
S_IROTH 00004 /* Read by others. */
S_IWOTH 00002 /* Write by others. */
S_IXOTH 00001 /* Execute by others. */
S_IRWXO 00007 /* Read, write, and execute by others. */
这里所有数字都是以八进制表示的,所以在数字面都由0(零)来开头,就以套接字文件为例,一共是7位数,从左到右,也就是从高位到低位来说,第一位对应表示八进制,第二、三位表示文件类型,因文件类型由四位二进制数字组成,最大为15,换算成八进制为17,所以需要占两位,这里定义14(八进制)为套接字文件。第四位表示文件特殊权限(S),第五位表示文件所有者权限(U),第六位表示同组用户权限(G),第七位表示其他用户权限(O)。这样就共同组成了代表套接字文件宏定义所代表的数值:0140000。在这里使用的是八进制数字。
以S_IFMT的宏定义为例,介绍一下S_IFMT函数在实际使用中的作用。
使用一个switch语句做一个简单的例程来识别文件的类型:
switch (file_stat.st_mode & S_IFMT) {
case S_IFSOCK:
printf("socketn"); break;
case S_IFLNK:
printf("symbolic linkn"); break;
case S_IFREG:
printf("regular filen"); break;
case S_IFBLK:
printf("block devicen"); break;
case S_IFDIR:
printf("directoryn"); break;
case S_IFCHR:
printf("character devicen"); break;
case S_IFIFO:
printf("FIFOn"); break;
}
除了这种方式,Linux系统还提供了封装好的宏,直接调用来判断文件类型,下面的mode是st_mode变量。
S_ISSOCK(mode) #判断是否为套接字文件
S_ISLNK(mode) #判断是否为链接文件
S_ISREG(mode) #判断是否为普通文件
S_ISBLK(mode) #判断是否为块设备文件
S_ISDIR(mode) #判断是否为目录
S_ISCHR(mode) #判断是否为字符设备文件
S_ISFIFO(mode) #判断是否为管道文件
注:以上的宏定义正确返回值为true,否则返回false。
用这些宏就可以来判断文件属性了。
5.示例:(使用stat函数获取文件属性)
| #include <stdio.h>
#include <stdlib.h> #include <sys/stat.h> #include <time.h> #include <unistd.h> void print_time(const char *label, time_t time) { struct tm *tm_info; char buffer[26]; tm_info = localtime(&time); strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info); printf("%s: %sn", label, buffer); } int main() { struct stat file_stat; const char *filename = "example.txt"; // 替换为你的文件名 // 获取文件状态信息 if (stat(filename, &file_stat) == -1) { perror("stat"); exit(EXIT_FAILURE); } // (1) 获取文件的 inode 节点编号和文件大小 printf("Inode number: %ldn", (long)file_stat.st_ino); printf("File size: %ld bytesn", (long)file_stat.st_size); // (2) 判断文件的其他用户权限 printf("Readable by others: %sn", (file_stat.st_mode & S_IROTH) ? "Yes" : "No"); printf("Writable by others: %sn", (file_stat.st_mode & S_IWOTH) ? "Yes" : "No"); // (3) 获取文件的时间属性 print_time("Last access time", file_stat.st_atime); print_time("Last modification time", file_stat.st_mtime); print_time("Last status change time", file_stat.st_ctime); return 0; } |
6.测试结果
| Inode number: 5254391
File size: 12 bytes Readable by others: Yes Writable by others: No Last access time: 2024-08-09 11:12:18 Last modification time: 2024-08-09 11:11:50 Last status change time: 2024-08-09 11:11:50 |
第一行输出了inode编号,第二行输出文件大小,第三行输出其他用户的读权限,第四行是其他用户的写权限,最后三行分别为最后访问时间,最后修改时间,最后一次状态变更时间。
80