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)
blank

相关推荐

  • eric6教程(钉钉的使用方法和技巧)

    Eric6是Python编程语言的IDE程序,功能之强大,绝不输于Python平台下的任何IDE程序,占用内存低运行速度快足以令Eric6藐视群雄,最可贵的是与PyQt5结合的更是天衣无缝,简直就是开发GUI程序的绝配。PyQt5是赖以Python编程语言的外部GUI开发语言,其夯实的底层基础与强大的可视化界面设计让PyQt5成为Python语言GUI开发的佼佼者,更新速度之快,开发GUI程序的速度之快,可以说其它GUI开发语言所望尘莫及。虽说Eric6与PyQt5结合使用可快速开发GUI程序,但是

  • js 判断一个 object 对象是否为空

    js 判断一个 object 对象是否为空js判断一个object对象是否为空转载原文判断一个对象是否为空对象,本文给出三种判断方法:1.最常见的思路,for…in…遍历属性,为真则为“非空数组”;否则为“空数组”for(variinobj){//如果不为空,则会执行到这一步,返回truereturntrue}returnfalse//如果为空,返回false2.通过JSON自带的s

  • lucene通过tokenstream显示分词信息「建议收藏」

    lucene通过tokenstream显示分词信息「建议收藏」publicclassAnalyzerUtil{ publicstaticvoidmain(String[]args){ StandardAnalyzersa=newStandardAnalyzer(Version.LUCENE_45); Stringstr=”Iamcomefromjiangxifengchengtongtian.thisi

  • idea2021.11.3激活(JetBrains全家桶)

    (idea2021.11.3激活)最近有小伙伴私信我,问我这边有没有免费的intellijIdea的激活码,然后我将全栈君台教程分享给他了。激活成功之后他一直表示感谢,哈哈~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html08…

  • plsqldev8.0下载和注册码「建议收藏」

    plsqldev8.0下载和注册码「建议收藏」[b]关键词:PL/SQL,下载,plsqldev,注册码,plsqldev711,汉化文件[/b]PL/SQLDeveloper是一种集成的开发环境,专门用于开发、测试、调试和优化OraclePL/SQL存储程序单元,比如触发器等。PL/SQLDeveloper功能十分全面,大大缩短了程序员的开发周期。[url]http://www.kutoku.info/software…

  • mysql中exists的用法详解[通俗易懂]

    mysql中exists的用法详解[通俗易懂]前言在日常开发中,用mysql进行查询的时候,有一个比较少见的关键词exists,我们今天来学习了解一下这个exists这个sql关键词的用法,这样在工作中遇到一些特定的业务场景就可以有更加多样化的解决方案语法解释语法SELECTcolumn1FROMt1WHERE[conditions]andEXISTS(SELECT*FROMt2);说明括号中的子查询并不会返回具体的查询到的数据,只是会返回true或者false,如果外层sql的字段在子查询中存在则返回true,

    2022年10月23日

发表回复

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

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