C语言:stat、fstat、lstat、fstatat函数详解

1、stat、fstat、lstat函数头文件及原型

查看男人手册第2册man 2 stat

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.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;    /* 设备ID(如果是特殊文件) */
	off_t     st_size;    /* 总大小,以byte为单位 */
	blksize_t st_blksize; /* 文件系统I/O的块大小 */
	blkcnt_t  st_blocks;  /* 分配的512B块数 */
	time_t    st_atime;   /* 最后访问时间 */
	time_t    st_mtime;   /* 最后修改时间 */
	time_t    st_ctime;   /* 上次状态更改的时间 */
};

int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstatat(int dirfd, const char *pathname, struct stat *buf,
			int flags);

  stat与lstat差别就在于l(link),stat会越过符号链接(软链接)读取源文件,后者则读取软链接文件。关于Linux环境的软硬链接可以参考:https://blog.csdn.net/weixin_44498318/article/details/105399439

可以使用以下宏传递结构体成员st_mode查看文件类型:

S_ISREG(m)		常规文件
S_ISDIR(m)		目录
S_ISCHR(m)		字符设备
S_ISBLK(m)		块设备
S_ISFIFO(m)		FIFO文件
S_ISLNK(m)		符号链接
S_ISSOCK(m)		套接字文件

事实上以下就是st_mode字段定义的标志,也可以相“&”来读取文件的属性:

S_IFMT     0170000   文件类型的位遮罩
S_IFSOCK   0140000   套接字
S_IFLNK    0120000   符号连接
S_IFREG    0100000   普通文件
S_IFBLK    0060000   块设备
S_IFDIR    0040000   目录
S_IFCHR    0020000   字符设备
S_IFIFO    0010000   FIFO
S_ISUID    0004000   文件的(set user-id on execution)位
S_ISGID    0002000   文件的(set group-id on execution)位
S_ISVTX    0001000   文件的sticky位
S_IRWXU    00700     文件所有者权限的掩码
S_IRUSR    00400     拥有者读权限
S_IWUSR    00200     拥有者写权限
S_IXUSR    00100     拥有者执行权限
S_IRWXG    00070     文件所在组权限的掩码
S_IRGRP    00040     用户组读权限
S_IWGRP    00020     用户组写权限
S_IXGRP    00010     用户组执行权限
S_IRWXO    00007     其他用户权限的掩码
S_IROTH    00004     其他用户读权限
S_IWOTH    00002     其他用户写权限
S_IXOTH    00001     其他用户执行权限

2、返回值

成功返回0,失败返回-1并且设置错误码errno;

3、示例

vi file.txt创建源文件,内容为hello,然后再ln -s file.txt file.txt.soft创建一个软链接文件(符号链接)。创建程序,内容如下:

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


int main()
{
        int fd;
        struct stat buf[3];

        // stat函数
        if( 0 != stat("./file.txt.soft", &buf[0]))
        {
                printf("stat error!\n");
                return -1;
        }
        printf("stat: The file size is %lu\n", buf[0].st_size);


        // fstat函数 
        fd = open("./file.txt.soft", O_RDWR);
        if(fd < 0)
        {
                printf("open file error!\n");
                return -1;
        }
        if(0 != fstat(fd, &buf[1]))
        {
                printf("fstat error!\n");
                return -1;
        }
        printf("fstat: The file size is %lu\n", buf[1].st_size);
        close(fd);


        // lstat函数
        if(0 != lstat("./file.txt.soft", &buf[2]))
        {
                printf("stat error!\n");
                return -1;
        }
        printf("lstat: The file size is %lu\n", buf[2].st_size);


        // 比较stat和lstat
        if(S_ISLNK(buf[0].st_mode))
                printf("stat: It is a link file!\n");
        else
                printf("stat: It is the file itself!\n");

        if(buf[2].st_mode & S_IFLNK)
                printf("lstat: It is a link file!\n");
        else
                printf("lstat: It is the file itself!\n");

        return 0;
}

gcc stat.c -o stat编译后./stat运行程序查看打印:

stat: The file size is 6
fstat: The file size is 6
lstat: The file size is 8
stat: It is the file itself!
lstat: It is a link file!

4、fstatat

  前面可以看到stat和lstat的区别就在于是否会越过符号链接(软链接文件)进行读取。那现在可以继续看fstatat了,主要看参数fd与参数flag:fd为AT_FDCWD时,pathname为相对路径,而若pathname给的是绝对路径,fd被忽略;flag为0时,就相当于stat,会透过符号链接(软链接文件)读取原文件,而等于AT_SYMLINK_NOFOLLOW时,就相当于lstat读取的是软链接文件本身:

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


int main()
{
        struct stat buf[2];

        if(fstatat(AT_FDCWD, "file.txt.soft", &buf[0], 0) < 0)
        {
                perror("fstatat1 error");
                return -1;
        }

		// if(fstatat(AT_FDCWD, "file.txt.soft", &buf[1], AT_SYMLINK_NOFOLLOW) < 0)	// 两者等价
        if(fstatat(AT_FDCWD, "/home/linriming/test/file.txt.soft", &buf[1], AT_SYMLINK_NOFOLLOW) < 0)
        {
                perror("fstatat2 error");
                return -1;
        }


        if(S_ISLNK(buf[0].st_mode))
                printf("flag = 0: It is a link file!\n");
        else
                printf("flag = 0: It is the file itself!\n");

        if(buf[1].st_mode & S_IFLNK)
                printf("flag = AT_SYMLINK_NOFOLLOW: It is a link file!\n");
        else
                printf("flag = AT_SYMLINK_NOFOLLOW: It is the file itself!\n");

        return 0;
}

/*
输出结果:
flag = 0: It is the file itself!
flag = AT_SYMLINK_NOFOLLOW: It is a link file!
*/
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

R-QWERT

你的鼓励是我最大的动力!

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

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

打赏作者

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

抵扣说明:

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

余额充值