嵌入式Linux系统编程 — 3.2 stat、fstat 和 lstat 函数查看文件属性

目录

1 文件有哪些属性

2 stat函数

2.1 stat函数简介

2.2 struct stat 结构体

2.3 struct timespec 结构体

2.4 示例程序

3  fstat 和 lstat 函数

3.1 fstat 函数

3.2 lstat 函数


1 文件有哪些属性

Linux文件属性是对文件和目录的元数据描述,包括文件类型、权限设置、所有者、所属组、文件大小、修改时间、状态更改时间、访问时间、inode号、链接数以及文件系统等,这些属性通过命令如ls -lstat可以查看,它们定义了文件的访问权限和存储细节,是Linux系统管理文件的基础。

2 stat函数

2.1 stat函数简介

Linux 下可以使用 stat 命令查看文件的属性,命令内部就是通过调用 stat()函数来获取文件属性的, stat 函数是 Linux 中的系统调用,用于获取文件相关的信息,函数原型如下所示(可通过"man 2 stat"命令查看) :

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

int stat(const char *pathname, struct stat *buf);

pathname: 用于指定一个需要查看属性的文件路径。
buf: struct stat 类型指针,用于指向一个 struct stat 结构体变量。调用 stat 函数的时候需要传入一个 structstat 变量的指针, 获取到的文件属性信息就记录在 struct stat 结构体中,结构体含义见2.2节。
返回值: 成功返回 0;失败返回-1,并设置 error。

2.2 struct stat 结构体

struct stat结构体用于存储由stat()系统调用返回的文件信息,在<sys/stat.h>头文件中申明,结构体内容如下所示:

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; /* 设备号(指针对设备文件) */
    off_t st_size; /* 文件大小(以字节为单位) */
    blksize_t st_blksize; /* 文件内容存储的块大小 */
    blkcnt_t st_blocks; /* 文件内容所占块数 */
    struct timespec st_atim; /* 文件最后被访问的时间 */
    struct timespec st_mtim; /* 文件内容最后被修改的时间 */
    struct timespec st_ctim; /* 文件状态最后被改变的时间 */
};

关于st_mode参数可参考文章4.1节:嵌入式Linux系统编程 — 1.1 文件I/O基础-CSDN博客

t_mode参数中包含“文件类型”,“文件类型”用4 个 bit 位表示,并有相应的宏定义, 这 4 个 bit 位用于描述该文件的类型,譬如该文件是普通文件、还是链接文件、亦或者是一个目录等,那么就可以通过这 4 个 bit 位数据判断出来,如下所示:

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(管道文件)

上面这些数字使用的是八进制方式来表示的,在 C 语言中,八进制方式表示一个数字需要在数字前面添加一个 0。所以由上面可知,当“文件类型”这 4 个 bit 位对应的数字是 14(八进制)时,表
示该文件是一个套接字文件。

所以通过 st_mode 变量可以判断文件类型,如下(假设 st 是 struct stat 类型变量) :

/* 判断是不是普通文件 */
if ((st.st_mode & S_IFMT) == S_IFREG) {
    /* 是 */
}
/* 判断是不是链接文件 */
if ((st.st_mode & S_IFMT) == S_IFLNK) {
    /* 是 */
}

除了这样判断之外,我们还可以使用 Linux 系统封装好的宏来进行判断,如下所示(m 是 st_mode变量) :

S_ISREG(m) #判断是不是普通文件,如果是返回 true,否则返回 false
S_ISDIR(m) #判断是不是目录,如果是返回 true,否则返回 false
S_ISCHR(m) #判断是不是字符设备文件,如果是返回 true,否则返回 false
S_ISBLK(m) #判断是不是块设备文件,如果是返回 true,否则返回 false
S_ISFIFO(m) #判断是不是管道文件,如果是返回 true,否则返回 false
S_ISLNK(m) #判断是不是链接文件,如果是返回 true,否则返回 false
S_ISSOCK(m) #判断是不是套接字文件,如果是返回 true,否则返回 false

有了这些宏之后,就可以通过如下方式来判断文件类型了:

/* 判断是不是普通文件 */
if (S_ISREG(st.st_mode)) {
    /* 是 */
}

/* 判断是不是目录 */
if (S_ISDIR(st.st_mode)) {
    /* 是 */
}

2.3 struct timespec 结构体

该结构体定义在<time.h>头文件中, 是 Linux 系统中时间相关的结构体,结构体内容如下所示:

struct timespec
{
    time_t tv_sec; /* 秒 */
    syscall_slong_t tv_nsec; /* 纳秒 */
};
  • tv_sec:表示自1970年1月1日(UTC时间)以来的秒数,这是一个time_t类型的值。
  • tv_nsec:表示tv_sec之后的纳秒数,范围从0到999,999,999。这个字段用于提供比秒更精确的时间度量。

2.4 示例程序

下面的代码通过命令行接收一个文件名作为参数,并使用stat系统调用来获取该文件的状态信息。

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>

// 函数用于将time_t类型的时间转换为可读的字符串格式并打印
void print_time(time_t time) {
    struct tm *tm_info; // 用于存储本地时间信息的结构体
    char buffer[26];    // 用于存储格式化时间的字符串

    tm_info = localtime(&time); // 将time_t转换为本地时间
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info); // 格式化时间
    printf("%s\n", buffer); // 打印格式化后的时间字符串
}

int main(int argc, char *argv[]) {
    struct stat file_stat; // 用于存储文件状态的结构体

    // 检查命令行参数数量,确保有文件名提供
    if (argc < 2) {
        printf("Usage: %s <filename>\n", argv[0]);
        return 1;
    }

    // 使用stat系统调用来获取文件状态
    if (stat(argv[1], &file_stat) == -1) {
        perror("Error getting file status"); // 打印错误信息
        return 1;
    }

    // 打印文件的inode节点编号和文件大小
    printf("Inode: %ld\n", (long)file_stat.st_ino);
    printf("Size: %lld bytes\n", (long long)file_stat.st_size);

    // 判断文件类型并打印
    switch (file_stat.st_mode & S_IFMT) {
        case S_IFREG:
            printf("Regular file\n");
            break;
        case S_IFDIR:
            printf("Directory\n");
            break;
        // 可以添加更多的文件类型判断
        default:
            printf("Unknown type\n");
    }

    // 检查其他用户的权限
    if (file_stat.st_mode & S_IROTH && file_stat.st_mode & S_IWOTH)
        printf("Other users have read and write permissions\n");
    else
        printf("Other users do not have read and write permissions\n");

    // 打印文件的时间属性
    printf("Last accessed: ");
    print_time(file_stat.st_atime);
    printf("Last modified: ");
    print_time(file_stat.st_mtime);
    printf("Status was last changed: ");
    print_time(file_stat.st_ctime);
    printf("\n");

    return 0;
}

程序定义了一个print_time函数,用于将time_t类型的时间戳转换为易读的日期和时间字符串格式,并将其打印出来。在main函数中,首先检查是否提供了足够的命令行参数,然后获取文件状态,打印文件的inode编号、大小、类型以及其他用户的读写权限。最后,程序调用print_time函数打印文件的最后访问时间、最后修改时间和状态最后改变时间。程序运行结果如下:

3  fstat 和 lstat 函数

3.1 fstat 函数

除了 stat 函数之外,还可以使用 fstat 和 lstat 两个系统调用来获取文件属性信息。

fstat 与 stat 区别在于, stat 是从文件名出发得到文件属性信息,不需要先打开文件;而 fstat 函数则是从文件描述符出发得到文件属性信息,所以使用 fstat 函数之前需要先打开文件得到文件描述符。

#include <sys/stat.h>
#include <unistd.h>

int fstat(int filedes, struct stat *buf);
  • filedes:指定要获取状态的文件描述符。
  • buf:指向一个 struct stat 结构体的指针,该结构体用于接收文件的状态信息。

fstat 函数使用示例如下:

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

int main() {
    FILE *file = fopen("example.txt", "w"); // 使用标准I/O库打开文件
    if (file == NULL) {
        perror("Failed to open file");
        return 1;
    }

    struct stat file_stat;
    if (fstat(fileno(file), &file_stat) == -1) { // 使用文件流获取文件描述符并获取状态信息
        perror("Failed to get file status");
        fclose(file);
        return 1;
    }

    printf("File size: %lld bytes\n", (long long)file_stat.st_size);

    fclose(file); // 使用标准I/O库关闭文件
    return 0;
}

代码使用 fstat 函数通过 fopen 得到的文件流获取文件状态信息,包括文件大小。然后,它打印出文件的大小。运行结果如下:

3.2 lstat 函数

lstat()与 stat、 fstat 的区别在于,对于符号链接文件, stat、 fstat 查阅的是符号链接文件所指向的文件对应的文件属性信息,而 lstat 查阅的是符号链接文件本身的属性信息。lstat 函数原型如下所示:

#include <sys/stat.h>
#include <unistd.h>

int lstat(const char *path, struct stat *buf);
  • path:指定要获取状态的文件或链接的路径。
  • buf:指向一个 struct stat 结构体的指针,该结构体用于接收文件或链接的状态信息。

  • 12
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

几度春风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值