ARM技术论坛
直播中

嵌入式小能手

2年用户 1514经验值
擅长:嵌入式技术
私信 关注
[经验]

飞凌嵌入式ElfBoard-获取文件的状态信息之stat

用来获取文件的详细状态信息。它可以用来检索与文件相关的属性,如文件的权限、所有者、大小、时间戳等信息。
1.头文件
#include
#include
#include
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结构体是在头文件中定义的,其中包含了文件的各种状态信息,
上面的结构体定义基本定义已经在注释中介绍完了,
需要注意的是结构体在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("socket\n"); break;
    case S_IFLNK:
        printf("symbolic link\n"); break;
    case S_IFREG:
        printf("regular file\n"); break;
    case S_IFBLK:
        printf("block device\n"); break;
    case S_IFDIR:
        printf("directory\n"); break;
    case S_IFCHR:
        printf("character device\n"); break;
    case S_IFIFO:
        printf("FIFO\n"); 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
#include
#include
#include
#include

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: %s\n", 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: %ld\n", (long)file_stat.st_ino);
    printf("File size: %ld bytes\n", (long)file_stat.st_size);

    // (2) 判断文件的其他用户权限
    printf("Readable by others: %s\n", (file_stat.st_mode & S_IROTH) ? "Yes" : "No");
    printf("Writable by others: %s\n", (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编号,第二行输出文件大小,第三行输出其他用户的读权限,第四行是其他用户的写权限,最后三行分别为最后访问时间,最后修改时间,最后一次状态变更时间。

更多回帖

发帖
×
20
完善资料,
赚取积分