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
运行截图