Linux stat函数_python系统调用函数

Linux stat函数_python系统调用函数Linux系统调用函数stat详解,以及文件信息结构体structstat结构体详解。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺


在这里插入图片描述


?1. inode节点与硬链接

在这里插入图片描述
通过上图可以看到,硬链接和源文件引用的是同一个inode节点,并且在inode节点中有一条硬链接计数信息,每当inode被引用一次,这个硬链接计数就会加1,我们可以通过ls命令来查看inode节点信息。我们先建立一个文件以及该文件的硬链接,通过ll命令可以查看文件信息(实际上这些信息就是存在inode节点中的信息)。
在这里插入图片描述
可以看到,建立一个硬链接之后,硬链接计数增加了1个。通过ls命令的-i选项可以查看文件的inode节点编号。
在这里插入图片描述
硬链接文件和源文件的inode节点编号一样,说明它们引用的是同一个inode节点。

在上图中的目录项中,有一条信息是类型,如果当前是目录的话,可以继续进入下一级目录。简单举个例子,比如说我们使用vi打开当前目录可以得到下面的内容。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AXC0o1lo-1653311503984)(./Typora_picture_reference/1652516397217.png)]
这里面的三个条目是当前文件夹下的文件,我们可以通过tree命令查看一下当前文件夹./的目录结构
在这里插入图片描述
当我们把光标停在某一文件所在行按回车键就可以查看该文件内容,如果这个文件是目录,就会进入该目录并显示目录下的条目。

比如,进入file.txt文件
在这里插入图片描述
进入目录111
在这里插入图片描述

?2. stat函数与 struct stat 结构体

  • 包含头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
  • 函数原型
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
  • 函数功能

    Get file status – These functions return information about a file.

  • 函数参数

    • path:指定文件

    • buf:buf是一个传出参数,也就是一级指针做输出,我们应该先定义一个结构体变量,并把该变量取地址&传给形参。

      struct stat 
      { 
             
      	dev_t     st_dev;     /* ID of device containing file */
      	ino_t     st_ino;     /* inode number */
          mode_t    st_mode;    /* protection 实际上就是权限位 */
          nlink_t   st_nlink;   /* number of hard links */
          uid_t     st_uid;     /* user ID of owner */
          gid_t     st_gid;     /* group ID of owner */
          dev_t     st_rdev;    /* device ID (if special file) */
          off_t     st_size;    /* total size, in bytes 文件大小 */
          blksize_t st_blksize; /* blocksize for file system I/O 块大小 */
          blkcnt_t  st_blocks;  /* number of 512B blocks allocated 块的个数 */
          time_t    st_atime;   /* time of last access 最后访问时间 */
          time_t    st_mtime;   /* time of last modification 最后修改时间 */
          time_t    st_ctime;   /* time of last status change 最后状态改变时间 */
      };
      
      • 对于结构体struct stat中的 mode_t st_mode 进行简要介绍(下面并没有全部列出,只列出了部分),首先是判断文件类型的两种方法。第一种是掩码的方式。

        S_IFMT     0170000   bit mask for the file type bit fields
        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 管道
        

        这个实际上就是我们ll命令查看文件时,第一列所显示的文件类型,在上面列出的内容中,中间一列数字用来标识文件类型,从S_IFSOCK到S_IFIFO就是我们所熟知的7种文件类型,S_IFMT是文件类型的掩码。通过和S_IFMT的与运算,就可以把标识文件类型的位保留下来(也就是前两个数017,第一个0表示8进制,后面17共四位 1 111 用来标识文件类型,那么S_IFMT用二进制表示就是1111后面加12个0,通过与与运算就把后面12位置为0而保留代表文件类型的四个bit,再把相与的结果与下面的S_IFSOCK到S_IFIFO进行对比来判断文件类型),进而判断文件类型。比如,现在有一个0041100,把它和S_IFMT做与运算结果为

        0041100 & 0170000 =  0040000		
        		  (S_IFMT)  (S_IFDIR)
        

        通过结果对比可以得出这是一个目录文件。这是通过掩码的方式来判断文件类型。

        另外一种判断文件类型的方法是使用它为我们提供的宏来判断,7种文件类型判断相关的宏如下所示,这里的m是指stat结构体中的st_mode。

        S_ISREG(m)  is it a regular file?
        S_ISDIR(m)  directory?
        S_ISCHR(m)  character device?
        S_ISBLK(m)  block device?
        S_ISFIFO(m) FIFO (named pipe)?
        S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)
        S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
        

        最后就是用户、组、其他用户的权限位(4位掩码,第一个0表示8进制)

        S_IRWXU    00700     mask for file owner permissions
        S_IRUSR    00400     owner has read permission
        S_IWUSR    00200     owner has write permission
        S_IXUSR    00100     owner has execute permission
        S_IRWXG    00070     mask for group permissions
        S_IRGRP    00040     group has read permission
        S_IWGRP    00020     group has write permission
        S_IXGRP    00010     group has execute permission
        S_IRWXO    00007     mask for permissions for others (not in group)
        S_IROTH    00004     others have read permission
        S_IWOTH    00002     others have write permission
        S_IXOTH    00001     others have execute permission
        
      • st_mode 各位含义示意图

      在这里插入图片描述

      • 结构体struct stat中的时间time_t也是一个结构体,它的原型如下

        struct timespec
        { 
                 
            _kernel_time_t 	tv_sec; /*seconds 当前时间到1970.1.1 0:0:0的秒数*/
            long 			tv_nsec; /*nanoseconds 纳秒*/
        }
        
  • 函数返回值

    成功返回0,失败返回-1并设置errno 。On success, zero is returned. On error, -1 is returned, and errno is set appropriately.

?3. stat函数实例分析及stat命令

下面通过一个实例来演示一下stat函数的使用方法。测试函数如下

/************************************************************ >File Name : getstat.c >Author : QQ >Company : QQ >Create Time: 2022年05月14日 星期六 18时37分17秒 ************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char* argv[])
{ 
   
	if(argc < 2)
	{ 
   
		printf("not found filename\n");
		return -1;	
	}
	struct stat m_status;
	stat(argv[1], &m_status);
	return 0;
}

我们可以借助gdb调试器来查看结构体内容,并且借助gdb强大的功能可以很优美的打印出结构体内容。
在这里插入图片描述
我们使用set来设置一下,优美的打印结构体
在这里插入图片描述
该文件的硬链接数为st_nlink=2,我们确实对该文件创建了硬链接
在这里插入图片描述
我们可以看到这里面有一个st_mode=33188,这个就是我们在介绍stat结构体时重点介绍的权限参数,但是这里是十进制显示的,我们可以把它的八进制形式在gdb中打印出来
在这里插入图片描述
我们通过这个8进制数和文件类型掩码、权限掩码分别相与就可以得到这个文件的文件类型以及各用户的权限。

S_IFMT & 0100644 = 0100000 ===>  S_IFREG    0100000

可以看到相与之后的值对应于S_IFREG,也就是说这是个普通文件。

继续往下看 st_uid=0,st_gid=0,这个对应的是用户及组ID,这里要说明的是,我当前使用的是root用户,相应用户的ID可以在 /etc/passwd 中查看,我们可以使用vim编辑器打开文件查看

vim /etc/passwd

在这里插入图片描述
在第一行就可以看到root,后面两个0就对应结构体中的 st_uid=0和st_gid=0 。

继续往下看st_size = 11表示文件大小,可以通过ll命令来验证一下
在这里插入图片描述
再后面是块大小st_blksize = 4096和块的个数st_blocks = 8,那么每个块的大小是512,实际上这两个内容就是记录有多少个512大小的块。

再后面就是三个时间结构体的信息,最近访问时间、最近更改时间、最近状态改动时间。

  • Access 最近访问时间:是指最近的一次访问(读/写等),比如使用cat、touch等命令访问了该文件(访问但是没有修改),那么最近访问时间就会更新;
  • Modify 最近更改时间:是指最近一次文件内容的更改时间;
  • Change 最近状态改动时间:是指最近一次文件属性的更改时间,文件属性的更改包括文件大小、硬链接计数、文件权限等等的修改,并且一般Modify发生改变的时候,Change也会随之变化,因为文件内容的修改一般都会涉及到文件大小等的变化;

如果我们只是用cat查看一下文件,那么只有Access时间会更新;如果我们只是修改文件的权限,比如增加可执行权限,那么只有Change时间更新;如果我们使用重定向往文件中写入内容,那么Modify和Change时间会更新,而Access时间不会更新,因为在重定向的过程中,并没有访问文件。

实际上,上面介绍的这些内容,直接通过stat命令就可以查看
在这里插入图片描述

?4. 实现 ls -l filename命令

我们可以通过stat函数来实现 ls -l 命令的功能,下面我们实现查看指定文件的 ls -l 命令,即

ls -l filename

实现代码如下

/************************************************************ >File Name : mls.c >Author : QQ >Company : QQ >Create Time: 2022年05月15日 星期日 16时29分01秒 >实现目标:-rw-r--r--. 2 root root 11 5月 14 15:02 file.txt ************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>

int main(int argc, char* argv[])
{ 
   
	if(argc < 2)
	{ 
   
		printf("not found filename\n");
		return -1;
	}
	/*通过stat函数获取文件信息*/
	struct stat fstatus;
	stat(argv[1], &fstatus); /*穿透*/
    /*lstat(argv[1], &fstatus); 非穿透 */
	/*解析文件信息,st_mode st_uid st_gid time*/
	/*-rw-r--r--.*/
	char stmode[11];
	memset(stmode, '-', sizeof(stmode));
	/*使用宏来判断文件属性*/
	if(S_ISREG(fstatus.st_mode)) /* regular file */
	{ 
   
		stmode[0] = '-';
	}
	if(S_ISDIR(fstatus.st_mode))
    { 
   
		stmode[0] = 'd';
	}
	if(S_ISCHR(fstatus.st_mode))
	{ 
   
		stmode[0] = 'c';
	}
	if(S_ISBLK(fstatus.st_mode))
	{ 
   
		stmode[0] = 'b';
	}
    if(S_ISFIFO(fstatus.st_mode))
	{ 
   
		stmode[0] = 'p';
	}
	if(S_ISLNK(fstatus.st_mode))
	{ 
   
		stmode[0] = 'l';
	}      
	if(S_ISSOCK(fstatus.st_mode))
	{ 
   
		stmode[0] = 's';
	}
	/*解析权限位*/
	if(fstatus.st_mode & S_IRUSR) 
	{ 
   /*为真表示拥有该权限,否则无权限,因为整块内存已初始化为 - 所以不需要else分支*/
		stmode[1] = 'r';
	}
	if(fstatus.st_mode & S_IWUSR) 
	{ 
   
		stmode[2] = 'w';
	}
	if(fstatus.st_mode & S_IXUSR) 
	{ 
   
		stmode[3] = 'x';
	}
	if(fstatus.st_mode & S_IRGRP) 
	{ 
   
		stmode[4] = 'r';
	}
	if(fstatus.st_mode & S_IWGRP) 
	{ 
   
		stmode[5] = 'w';
	}
	if(fstatus.st_mode & S_IXGRP) 
	{ 
   
		stmode[6] = 'x';
	}
	if(fstatus.st_mode & S_IROTH) 
	{ 
   
		stmode[7] = 'r';
	}
	if(fstatus.st_mode & S_IWOTH) 
	{ 
   
		stmode[8] = 'w';
	}
	if(fstatus.st_mode & S_IXOTH) 
	{ 
   
		stmode[9] = 'x';
	}
	stmode[10] = '\0';
	
	/*获取时间 localtime() 函数(非系统调用) *原型:struct tm *localtime(const time_t *timep); *参数:time_t类型,struct stat中time_t st_atime,这里应该是文件访问时间 *返回:struct tm { int tm_sec; seconds (0-60 ) int tm_min; minutes (0-59) int tm_hour; hours (0-23) int tm_mday; day of the month (1-31) int tm_mon; month (0-11) int tm_year; year (-1900) 如果要求实际年份,应加上1990 int tm_wday; day of the week sunday=0 int tm_yday; day in the year int tm_isdst; daylight saving time }; */
	struct tm* filetime = localtime(&fstatus.st_atim.tv_sec);
	char timebuf[20] = { 
   0};
	sprintf(timebuf, "%d月 %d %02d:%02d", \
					filetime->tm_mon + 1, \
					filetime->tm_mday, \
					filetime->tm_hour, \
					filetime->tm_min);
					
	/*打印格式 -rw-r--r--. 2 root root 11 5月 14 15:02 file.txt*/
	printf("%s %ld %s %s %ld %s %s\n", \
			stmode, \
			fstatus.st_nlink, \
			getpwuid(fstatus.st_uid)->pw_name, \
			getgrgid(fstatus.st_gid)->gr_name, \
			fstatus.st_size, \
			timebuf, \
			argv[1]);
			
	/* 两个函数(非系统调用) struct passwd *getpwuid(uid_t uid); 根据uid获取用户信息 struct passwd { char *pw_name; username char *pw_passwd; user password uid_t pw_uid; user ID gid_t pw_gid; group ID char *pw_gecos; real name char *pw_dir; home directory char *pw_shell; shell program }; struct group *getgrgid(gid_t gid); 根据gid获取组信息 struct group { char *gr_name; group name char *gr_passwd; group password gid_t gr_gid; group ID char **gr_mem; group members }; */
	
	return 0;
}

测试一下效果
在这里插入图片描述

?5. 穿透与非穿透

上面介绍了stat函数并通过stat函数实现了 ls -l 命令的功能。我们上面演示了使用自己实现的 ./mls 查看文件信息,假如说使用 ./mls 查看一个链接文件是什么效果呢,下面演示一下。
在这里插入图片描述
通过对比我们可以看到,符号链接(软链接)file.txt.soft的实际大小是8,但是我们自己实现的 ./mls 命令显示的大小是11。实际上,原因是这样的,我们在实现 ./mls 命令的时候是基于stat函数来获取文件信息的,stat函数有一个特性就是在获取链接文件信息的时候会进行穿透,去追溯符号链接的源文件,也就是说我们通过上面的命令 ./mls file.txt.soft 获取到的大小实际上是源文件file.txt的大小,我们可以验证一下。
在这里插入图片描述
那么我们自己如何实现获取符号链接的实际大小呢,这就用到了非穿透函数lstat,只要把上面代码实现中的函数调用stat替换为lstat就可以了,下面测试一下。

lstat(argv[1], &fstatus);

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/171805.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 0603贴片电阻阻值对照表_贴片电阻快速识别表与识别方法[通俗易懂]

    0603贴片电阻阻值对照表_贴片电阻快速识别表与识别方法[通俗易懂]贴片电阻快速识别表与识别方法,要想快速识别贴片电阻,那就必须知道什么是贴片电阻?贴片电阻就是金属粉和玻璃釉粉混合,采用丝网印刷法印在基板上制成的电阻器。与贴片电容不一样的是,贴片电容一般比电容厚,且电阻两边为银白色镀锡,中间黑色。下面我们来看看具体的两个识别方法。快速识别贴片电阻,方法一:如上图所示,正面主要是中间黑色带电阻代码,方便识别贴片电阻大小,两头是锡面,银白色,方便焊接。背面中间是高纯度…

  • IplImage中的widthStep大小计算及原理[通俗易懂]

    IplImage中的widthStep大小计算及原理[通俗易懂]一直以为IplImage结构体中的widthStep元素大小等于width*nChannels,大错特错!查看OpenCV2.1的源码,在src/cxcore/cxarray.cpp文件中,找到cvInitImageHeader函数,函数中对widthStep大小赋值如下:image->widthStep=(((image->width*image->nChannels*

  • Java 生成 UUID[通俗易懂]

    Java 生成 UUID[通俗易懂]1.UUID简介UUID含义是通用唯一识别码(UniversallyUniqueIdentifier),这是一个软件建构的标准。也是被开源软件基金会(OpenSoftwareFou

  • eclipse添加logcat显示_eclipse的logcat不见了

    今天打开eclipse调了一会程序,突然发现logcat不见了,只有Console等,找了半天没找到,最后还是苦命的发现了,如下.Window ……Show View……Other…会出现如下对话框:选择LogCat后,eclipse就能正常查看LogCat的输出了。

  • kong优化参考[通俗易懂]

    kong优化参考[通俗易懂]KongAPIGateway配置文件详解2018-09-24/Linuxops版权说明:本文为博主原创,如果转载请注明来源。作为学习笔记,不能保证所有知识点是完全正确以及表达无误,用于生产环境配置时请斟酌。如有错误或建议请联系。侵删联系:linuxops@qq.com。感谢各位!一、前言Kong配置文件是Kong服务的核心文件,它配置了Kong以怎么的方式运行,并且…

  • oracle12官方下载,Oracle 12c下载64位|Oracle Database 12c下载 官方版_最火软件站[通俗易懂]

    oracle12官方下载,Oracle 12c下载64位|Oracle Database 12c下载 官方版_最火软件站[通俗易懂]Oracle12C是由Oracle官方提供的最新版本数据库,Oracle12C引入了CDB与PDB的新特性,在ORACLE12C数据库引入的多租用户环境(MultitenantEnvironment)中,允许一个数据库容器(CDB)承载多个可插拔数据库(PDB)。CDB全称为ContainerDatabase,中文翻译为数据库容器,PDB全称为PluggableDatabase,即可…

    2022年10月28日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号