嵌入式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 结构体的指针,该结构体用于接收文件或链接的状态信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/690768.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录-算法训练营day61【代码随想录-算法训练营-总结】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 算法训练营&#xff0c;60天&#xff0c;包含这些内容&#xff1a; 01、数组 02、链表 03、哈希表 04、字符串 05、双指针法 06、栈与队列 07、二叉树 08、回溯算法 09、贪心算法 10、动态规划 11、单调栈 12、图论 做…

数据库同步软件PanguSync常见错误解决方法

​​​​​​在部署PanguSync数据库同步软件的过程中&#xff0c;常常会遇见一些错误提示&#xff0c;某些老铁可能会一脸懵逼&#xff0c;本文对一些常见的错误信息进行了总结&#xff0c;并提供了解决方法。 1.")"附近有语法错误 该问题是由于源表未设置主键&…

安卓打造安装包(应用打包、规范处理安装包、安全加固)

本章介绍应用安装包的基本制作规范&#xff0c;主要包括&#xff1a;如何导出既美观又精简的APK文件、如何按照上线规范调整App的相关设置、如何对APK文件进行安全加固以防止安装包被破解。 应用打包 本节介绍APK安装包的打包过程&#xff0c;包括&#xff1a;如何利用Androi…

Java Web学习笔记21——前后端分离开发

前后端混合开发&#xff1a; 沟通成本比较高。 分工不明确。 不便管理&#xff0c;不便于后期的维护和拓展。 前后端分离开发&#xff1a; 当前主流的开发模式&#xff1a;前后端分离开发&#xff1a; 接口文档&#xff1a; 接口并不是interface。 接口指的是业务功能。 …

选择排序(直接选择排序与堆排序)----数据结构-排序②

1、选择排序 1.1 基本思想 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完就停止 。 1.2 直接选择排序 排序思想&#xff1a; ①在元素集合array[i]--array[n-1]中选择…

Java项目如何外发告警日志到企业微信

前言 最近领导交代了一个需求,就是有些许客户不单单满足平台告警日志外发到邮箱、短信的形式,还要以消息聊天的形式外发给企业微信。 具体操作 1、注册企业微信。 2、登录企业微信,找到应用管理,创建应用。 3、创建完之后需要记录以下图片中两个值的信息。 4、然后记录下…

stanfordcorenlp+python做中文nlp任务,得到的结果中全是空字符串,而不是中文字符串

问题描述 代码&#xff1a; from stanfordcorenlp import StanfordCoreNLP import logging#中文中的应用&#xff0c;一定记得下载中文jar包&#xff0c;并标志lang‘zh’ nlp_zh StanfordCoreNLP(rD:\stanford-corenlp-full-2016-10-31, port8094, langzh,quietFalse,logg…

【排序算法】总结篇

✨✨这些 排序算法都是指的 需要进行比较的排序算法 ✨✨下面都是略微讲解一下思路&#xff0c;如果需要详细了解哪一个排序&#xff0c;点击&#x1f449;链接即可 ✨✨对于时间、空间复杂度、稳定性&#xff0c;希望你&#x1f9d1;‍&#x1f393;能够理解记忆&#x1f9d1;…

SpeedyBee飞塔F405 V3 50A

遥控器常用的几种协议&#xff1a; 一文打尽PWM协议、PPM协议、PCM协议、SBUS协议、XBUS协议、DSM协议 | STM32的通用定时器TIM3实现PPM信号输出 - 蔡子CaiZi - 博客园 (cnblogs.com) SpeedyBee飞塔的官方教程&#xff1a; FlowUs 息流 - 新一代生产力工具 为8位电调刷写固…

【纯血鸿蒙】——自适应布局如何实现?

界面级一多能力有 2 类&#xff1a; 自适应布局: 略微调整界面结构 响应式布局&#xff1a;比较大的界面调整 本文章先主要讲解自适应布局&#xff0c;响应式布局再后面文章再细讲。话不多说&#xff0c;开始了。 自适应布局 针对常见的开发场景&#xff0c;方舟开发框架提…

融合创新:Web3如何重新定义网络生态

随着区块链技术的不断发展和Web3时代的到来&#xff0c;我们正在见证着互联网生态的巨大变革。Web3将传统的互联网架构转变为去中心化、开放、透明的新网络生态&#xff0c;为创新和合作提供了全新的可能性。本文将深入探讨Web3如何重新定义网络生态&#xff0c;探索融合创新的…

HAL STM32F1 通过查表方式实现SVPWM驱动无刷电机测试

HAL STM32F1 通过查表方式实现SVPWM驱动无刷电机测试 &#x1f4cd;相关篇《基于开源项目HAL STM32F4 DSP库跑SVPWM开环速度测试》 ✨针对STM32F1系列&#xff0c;没有专门的可依赖的DSP库&#xff0c;为了实现特定函数的浮点运算快速计算&#xff0c;通过查表方式来实现&#…

搭建多平台比价软件你必须知道的几大知识板块

为了搭建一个多平台比价系统并使其发挥作用&#xff0c;你需要考虑以下几个关键的平台支持方面&#xff1a; 数据API采集平台&#xff1a; 电商平台&#xff1a;如亚马逊、淘宝、京东等&#xff0c;这些平台提供了丰富的商品信息和价格数据。旅行服务平台&#xff1a;如携程、…

git凭证

默认是manager # 将凭证缓存到内存中&#xff0c;默认缓存15分钟 git config --global credential.helper cache# 将凭证存储到磁盘上的纯文本文件中 git config --global credential.helper store# 使用 Git 凭证管理器 git config --global credential.helper manager-core查…

红队神器Evil-winrm的使用

前言 Evil-winrm 工具最初是由 Hackplayers 团队开发的。开发该工具的目的是尽可能简化渗透测试&#xff0c;尤其是在 Microsoft Windows 环境中。 Evil-winrm 使用 PowerShell 远程协议 (PSRP)&#xff0c;且系统和网络管理员经常使用Windows Remote Management 协议进行上传和…

C++基础四:C++模板编程

目录 一:函数模板 二:类模板 空间配置器allocator 一:函数模板 模板代码只能同一实现,不能先声明,再在另一文件实现,模板代码都是放在头文件当中的,在头文件中直接实现 二:类模板 template<typename T=int> class SeqStack // 模板名称+类型参数列表 = 类名称…

2024 年最全的 21 款数据恢复工具软件汇总

使用其中任何一款免费数据恢复工具&#xff0c;您都可以找回那些您认为已经永远消失的文件。我根据这些程序对我而言的易用性和它们提供的功能对这些程序进行了排名。 这些应用程序从您的硬盘、USB 驱动器、媒体卡等恢复文档、视频、图像、音乐等。我建议每个计算机所有者都安装…

list模拟与实现(附源码)

文章目录 声明list的简单介绍list的简单使用list中sort效率测试list的简单模拟封装迭代器insert模拟erase模拟头插、尾插、头删、尾删模拟自定义类型迭代器遍历const迭代器clear和析构函数拷贝构造&#xff08;传统写法&#xff09;拷贝构造&#xff08;现代写法&#xff09; 源…

C盘满了怎么办,Windows11的C盘没有磁盘清理选项怎么办,一次搞定

问题&#xff1a; 太久没清电脑了&#xff0c;满的跟垃圾堆一样。。。C盘红色看上去很不妙。 一. C盘满了怎么办&#xff1a; 1. 删除临时文件 找到 C:\Windows\Temp&#xff0c;进入Temp资料夹&#xff0c;选中所有文件夹和文件&#xff0c;按下ShiftDelete键&#xff0c;彻…

张宇1000和李林880究竟哪个更难?

24李林跌落神坛&#xff0c;张宇一战封神&#xff01; 张宇1000和李林880&#xff0c; 谁的基础篇更“超纲”&#xff1f; 谁覆盖的知识点更多&#xff1f; 谁的概念题更多&#xff1f; 谁的“强化难度”题更难&#xff1f; 基础篇里为什么有“跨专题”的题&#xff0c;都…