Linux 文件目录信息打印stat+dirent

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

功能:得到文件的信息,将其保存在buf结构中;

参数:

对于stat() ,lstat()来说const char *path,是要查看属性的文件或目录的全路径名称

对于fstat来说int fd,为已打开的文件描述词

struct _stat *buffer:结构体对象地址

返回值:

成功返回     1,失败返回     0

struc stat 详解:

struct stat  
{   
    dev_t       st_dev;     /* ID of device containing file -文件所在设备的ID*/  
    ino_t       st_ino;     /* inode number -inode节点号*/    
    mode_t      st_mode;    /* protection -保护模式?*/    
    nlink_t     st_nlink;   /* number of hard links -链向此文件的连接数(硬连接)*/    
    uid_t       st_uid;     /* user ID of owner -user id*/    
    gid_t       st_gid;     /* group ID of owner - group id*/    
    dev_t       st_rdev;    /* device ID (if special file) -设备号,针对设备文件*/    
    off_t       st_size;    /* total size, in bytes -文件大小,字节为单位*/    
    blksize_t   st_blksize; /* blocksize for filesystem I/O -系统块的大小*/    
    blkcnt_t    st_blocks;  /* number of 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 - */    
};  

st_mode字段:

st_mode 一共有16位,主要包含了 3 部分信息:

  • 15-12 位保存文件类型
  • 11-9 位保存执行文件时设置的信息
  • 8-0 位保存文件访问权限 

 

图片来自网络

r=4 表示可读

w=2表示可写

x=1表示可执行

st_mode 的宏描述作用:

    S_IFMT   0170000    文件类型的位遮罩
    S_IFSOCK 0140000    scoket
    S_IFLNK 0120000     符号连接
    S_IFREG 0100000     一般文件
    S_IFBLK 0060000     区块装置
    S_IFDIR 0040000     目录
    S_IFCHR 0020000     字符装置
    S_IFIFO 0010000     先进先出

    S_ISUID 04000     文件的(set user-id on execution)位
    S_ISGID 02000     文件的(set group-id on execution)位
    S_ISVTX 01000     文件的sticky位

    S_IRUSR(S_IREAD) 00400     文件所有者具可读取权限
    S_IWUSR(S_IWRITE)00200     文件所有者具可写入权限
    S_IXUSR(S_IEXEC) 00100     文件所有者具可执行权限

    S_IRGRP 00040             用户组具可读取权限
    S_IWGRP 00020             用户组具可写入权限
    S_IXGRP 00010             用户组具可执行权限

    S_IROTH 00004             其他用户具可读取权限
    S_IWOTH 00002             其他用户具可写入权限
    S_IXOTH 00001             其他用户具可执行权限

 POSIX定义了下面几种通过st_mode判断文件类型的宏:

The following POSIX macros are defined to check the file type using the st_mode field:
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.) -套接口? */

DIR文件目录操作:

常用函数:

DIR* opendir (const char * path );

struct dirent *readdir(DIR *dp);   

void rewinddir(DIR *dp);   

int closedir(DIR *dp);   

long telldir(DIR *dp);   

void seekdir(DIR *dp,long loc);  

所需头文件:#include<sys/types.h>     #include<dirent.h>  


函数:DIR* opendir (const char * path );

功能:打开一个目录,在失败的时候返回一个空的指针。

         获取path子目录下的所由文件和目录的列表,如果path是个文件则返回值为NULL。

返回值(DIR):  DIR 结构体的原型为:struct_dirstream

 参数:const char * path   文件路径相对或者绝对


函数: struct dirent* readdir(DIR* dir_handle);

功能:读取opendir 返回值的那个列表,类似于read文件读取

返回值: dirent的结构类型

参数:DIR


函数:void rewinddir(DIR *dp);   

功能:用来设置参数dir目录流目前的读取位置为原来开头的读取位置,没有返回值的函数

返回值:void

参数:DIR


函数:int closedir(DIR *dp);

功能:关闭参数dir所指的目录流。关闭成功则返回0,失败返回-1,错误原因存于errno 中。EBADF 参数dir为无效的目录流。

注意:目录文件作为一种文件,再打开必须关闭,否则会由于文件的进程打开文件过多而不能打开新的文件。因此opendir函数和closedir函数同样是配对出现的。

返回值:关闭成功则返回0,失败返回-1

参数:DIR


函数:long telldir(DIR *dp);

功能:telldir()函数的返回值记录着一个目录流的当前位置。此返回值代表距离目录文件开头的偏移量返回值返回下个读取位置,有错误发生时返回-1。你可以在随后的seekdir函数调用中利用这个值来重置目录扫描到当前位置。错误代码 EBADF参数dir为无效的目录流。

返回值:有错误发生时返回-1。

参数:DIR


函数:void seekdir(DIR *dp,long loc);  

功能:seekdir()用来设置参数dir目录流当前的读取位置,在调用readdir()时便从此新位置开始读取。参数offset 代表距离目录文件开头的偏移量

返回值:错误代码 EBADF 参数dir为无效的目录流

参数:DIR   参数offset 代表距离目录文件开头的偏移量。


DIR结构体:

struct __dirstream
   {
    void *__fd;
    char *__data;
    int __entry_data;
    char *__ptr;
    int __entry_ptr;
    size_t __allocation;
    size_t __size;
    __libc_lock_define (, __lock)
   };
typedef struct __dirstream DIR;

相当于目录描述符用于存放目录下的子目录类似于文件描述符

struct dirent 结构体:

struct dirent
   
{
   
  long d_ino; /* inode number 索引节点号 */  
  
   
    off_t d_off; /* offset to this dirent 在目录文件中的偏移 */  
  
   
    unsigned short d_reclen; /* length of this d_name 文件名长 */  
  
   
    unsigned char d_type; /* the type of d_name 文件类型 */  
  
   
    char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */  
}  

LINUX系统下的一个头文件,在这个目录下/usr/include为了获取某文件夹目录内容,所使用的结构体


所需要的知识已经介绍完了接下来介绍怎样打印一个目录下的所有子目录的属性

这里直接使用递归操作,但是由于d_name是指向的是目录的名字不是路径所以只需要把文件路径保存下来进行递归操作就好,有值得注意的一点是当目录名称是"."或".."时不需要往下读去因为这样会进入死循环的。

代码:

头文件:head.h

#include <stdio.h>
#include <unistd.h> 
#include <stdlib.h>  
#include <string.h>  
#include <errno.h>  
#include <sys/types.h> 
#include <fcntl.h>
#include <sys/epoll.h>
#include <netinet/in.h>  
#include <sys/socket.h>  
#include <arpa/inet.h>  
#include <sys/select.h>
#include <math.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

#define MAX_N 1024
#define MAX_M 100
extern  char get_type(mode_t mod);
extern  void get_perm(mode_t mod,char *buf);
extern  void get_ltime(time_t *t,char *buf);
extern  void put_stat(char *dir,char *name);
extern  void get_dir(char *dir);


操作函数:oper.c

#include"./head.h"
//获取文件类型
char  get_type(mode_t mod)
{
	/*
	if( S_ISREG(mod) ) return '-';
       if( S_ISDIR(mod) ) return 'd';
       if( S_ISCHR(mod) ) return 'c';
       if( S_ISBLK(mod) ) return 'b';
       if( S_ISLNK(mod) ) return 'l';
       if( S_ISSOCK(mod) ) return 's';
       if( S_ISFIFO(mod) ) return 'p';
	*/
	switch(mod & S_IFMT)
    {
    case S_IFSOCK: return 's';//socket 套接字
    case S_IFREG: return '-';//普通文件
    case S_IFCHR: return 'c';//字符设备
    case S_IFBLK: return 'b';//块设备
    case S_IFLNK: return 'l';//符号链接
    case S_IFIFO: return 'p';//管道文件
    case S_IFDIR: return 'd';//目录文件
    }
}
//获取文件权限
void get_perm(mode_t mod,char *buf)
{
    bzero(buf,sizeof(buf));
    int i = 9;
    while(i--)
    {
        if(mod & 1<<i)
        {
            switch((8-i)%3)
            {
            case 0: buf[8-i] = 'r'; break;
            case 1: buf[8-i] = 'w'; break;
            case 2: buf[8-i] = 'x'; break;
            }
        }
        else
            buf[8-i] = '-';
    }
}
//获取文件最后一次修改时间
void get_ltime(time_t *t,char *buf)
{
	struct tm *tmp;
	tmp=localtime(t);
	sprintf(buf,"%d-%d-%d %d:%d:%d", (1900 + tmp->tm_year), ( 1 + tmp->tm_mon), tmp->tm_mday,
		tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 
	return ;
}
void put_stat(char *dir,char *name)
{
	struct stat s;
	if(-1 == stat(dir, &s) )
    {
        perror("stat");
        exit(0);
    }
	char buf_perm[MAX_M];
	get_perm(s.st_mode,buf_perm);//获取文件权限
	char buf_time[MAX_M];
	get_ltime(&s.st_ctime,buf_time);//获取文件最后一次修改时间
	printf( "%c%s %5d %15s %15s %15ld %15s  %15s  \033[0m\n", 
                get_type(s.st_mode),
                buf_perm,
                s.st_nlink,
                getpwuid(s.st_uid)->pw_name,
                getgrgid(s.st_gid)->gr_name,
                s.st_size, 
                buf_time,
                name );
	if(get_type(s.st_mode)=='d'&&strcmp(name,".")!=0&&strcmp(name,"..")!=0)//如果是一个目录就继续往下读
	{
		get_dir(dir);
	}
	return ;
}

void get_dir(char *dir)//读取文件
{

	DIR *dp = opendir(dir); //打开目录的子目录
    struct dirent *p;
	printf("%s:\n",dir);
	puts("{");
    while( p = readdir(dp) )//读取目录下的文件信息
    {
		char ttp[MAX_N];
		bzero(ttp,sizeof(ttp));
		strcat(ttp,dir);
		if(strcmp(ttp,"/")!=0)strcat(ttp,"/");//如果是根目录不需要加
		strcat(ttp,p->d_name);
        put_stat(ttp,p->d_name);
    }
	puts("}");
	return;
}

主函数:main.c

#include"./head.h"
int main(int argc,char *argv[])
{
	if(argc<2)  {perror("argc is not enough\n");return 0;}
	get_dir(argv[1]);
    return 0;
}

Makefile (局部万能)

SRC=$(wildcard *.c)
OBJ=$(patsubst %.c ,%.o,${SRC})
all=main
${all}:${OBJ}
	gcc -g -o $@ $^
.PHONY:
clean:
	rm  -rf *.o main 

运行截图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值