(1)、获取文件信息的函数:
- #include < sys / stat.h > int stat(const char * path, struct stat * buf);
- /*将path参数(文件或目录)的文件信息写到buf中,buf为传出参数*/
(2)、文件信息结构体:
- /*用不到的成员被注释掉,只需了解需要的成员即可*/
- struct stat {
- //dev_t st_dev;/*设备id号*/
- //ino_t st_ino;/*i节点号*/
- mode_t st_mode;
- /*权限与文件类型*/
- nlink_t st_nlink;
- /*硬链接数*/
- uid_t st_uid;
- /*用户id*/
- ggid_t st_gid;
- /*所在组id*/
- //dev_t st_rdev;/*设备id,对于特殊文件才有*/
- off_t st_size;
- /*大小,较为常用*/
- //blksize_t st_blocks;/*blocksize for file system I/O*/
- //blkcnt_t st_blksize;/*number of 512B blocks allocated*/
- //time_t st_atime;/*最后的访问时间*/
- time_t st_mtime;
- /*最后的修改时间,较为常用*/
- //time_t st_ctime;/*最后的状态改变时间*/
- }
①秒差形式,1970 年 1 月 1 日 0 时 0 分 0 秒的秒数差,得到的类型为 time_t;
②结构 (man time.h) 形式:
- struct tm {
- int tm_sec;
- /*Second [0,60].包含闰秒*/
- int tm_min;
- /*Minutes [0,59].*/
- int tm_hour;
- /*Hour [0,23].*/
- int tm_mday;
- /*Day of month [1,31].*/
- int tm_mon;
- /*Month of year [0,11].(January = 0)*/
- int tm_year;
- /*Year Since 1900.*/
- int tm_wday;
- /*Day of week [0,6] (Sunday = 0).*/
- int tm_yday;
- /*Day of year [0,365].包含闰年*/
- int tm_isdat;
- /*Daylight Savings flag*/
- /*夏时制,夏时令(Daylight Saving Time:DST)*/
- }
计算机大多数情况使用 time_t,因为效率高。但是显示时为 tm 结构形式。localtime() 函数可以实现: time_t 到 tm 的转换。time_t 的指针做参数,返回值 tm 的指针。
也可以使用: ctime 打印出美式时间显示方式(我们不采用)。
- char * time_buf = ctime(&st.st_mtime);
- printf("%s",time_buf);
由于 mode_t mode;参数中包含的信息不止一个需要根据不同的方式进行提取:
(1)、判断文件类型的宏函数:
- 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.)
- /*判断是否是SOCKET文件*/
当然也可以采用宏变量的方式,但是我更习惯用宏函数。
(2)、表示文件权限与类型的宏变量:
- The following flags are defined for the st_mode field:
- /*我们不会用到文件类型的宏变量(与宏函数功能类似)*/
- 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
- S_ISUID 0004000 set UID bit
- S_ISGID 0002000 set-group-ID bit (see below)
- S_ISVTX 0001000 sticky bit (see below)
- /*我们会用到的文件权限宏变量*/
- 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
- DIR * opendir(const char * name);
- /*打开一个目录*/
- struct dirent * readdir(DIR * );
- /*读目录,依次返回目录的子项(一次返回一个,读一个目录指针后移一次),到目录尾或出错时返回NULL,出错会设置errno*/
目录信息结构体 struct dirent:
- struct dirent{
- ino_t d_ino;//子项的i节点
- off_t d_off;//节点的偏移量
- unsigned short d_reclen;//长度
- unsigned char d_type;//子项类型(常用)
- char d_name[256];//子文件名(常用)
- };
其它函数与结构体这里就不再介绍,有不懂得可以去查 man 手册。
结果除了格式以外(没有排序),基本相同。对于最上面一层占空间大小没有写,有兴趣的可以自己加上该功能。并且代码是笔者一次性写完,并没有过多的进行测试,对于潜在 BUG 没有排除,可简化的代码也没有过多处理。
- /*filename:myls.h*/
- #ifndef _MYLS_H_
- #define _MYLS_H_
- #include<stdio.h>
- #include<stdlib.h>
- #include<string.h>
- #include<unistd.h>
- #include<dirent.h>
- #include<sys/stat.h>
- #include<fcntl.h>
- #include<sys/types.h>
- #include<pwd.h>
- #include<grp.h>
- #include<time.h>
- void error_print(const char *);
- void mylist_dir(const char *);
- void list_message(const char *,const struct stat *);
- void file_type(const struct stat *);
- void file_power(const struct stat *);
- void file_power_char(mode_t,mode_t,const char);
- void id_to_string(const struct stat *);
- void timet_to_tm(const struct stat *);
- #endif
- /*filename:myls.c*/
- #include < myls.h > void error_print(const char * ptr)
- /*错误处理*/
- {
- perror(ptr);
- exit(EXIT_FAILURE);
- }
- void mylist_dir(const char * pathname)
- /*读取目录中的文件*/
- {
- DIR * ret_opendir = opendir(pathname);
- /*打开传递的目录pathname*/
- if (ret_opendir == NULL)
- /*判断错误并处理*/
- error_print("opendir");
- int ret_chdir = chdir(pathname);
- /*先change dir到需要list的目录中*/
- if (ret_chdir == -1)
- /*判断错误并处理*/
- error_print("chdir");
- struct dirent * ret_readdir = NULL;
- /*定义接收readdir函数返回的结构体变量*/
- while (ret_readdir = readdir(ret_opendir)) {
- /*判断读取是否到目录尾*/
- char * filename = ret_readdir - >d_name;
- struct stat get_message = {};
- int ret_stat = stat(filename, &get_message);
- /*用stat函数读取filenmae文件的信息,并将结果写到get_message结构体中*/
- if (ret_stat == -1)
- /*stat函数不出错则进行信息输出*/
- error("stat %s", filename);
- else if (strcmp(filename, ".") && strcmp(filename, ".."))
- /*ls -l 不会输出当期那目录与上一级目录*/
- list_message(filename, &get_message);
- }
- }
- void list_message(const char * filename, const struct stat * get_message)
- /*处理读取到的文件*/
- {
- file_type(get_message);
- /*判断并打印文件类型*/
- file_power(get_message);
- /*判断并打印文件权限*/
- printf("%d ", get_message - >st_nlink);
- /*打印硬链接数*/
- id_to_string(get_message);
- /*用户id与组id转换成用户名与组名并打印*/
- printf("%d\t", get_message - >st_size);
- /*打印所占空间文件大小*/
- timet_to_tm(get_message);
- /*将GMT时间的秒数转换成标准时间格式输出*/
- printf("%s\n", filename);
- /*输出文件名*/
- }
- void file_type(const struct stat * get_message) {
- mode_t mode = ( * get_message).st_mode;
- if (S_ISREG(mode)) printf("-");
- /*普通文件*/
- else if (S_ISDIR(mode)) printf("d");
- /*目录文件*/
- #
- if 0
- else if (S_ISCHR(mode)) printf("c");
- /*字符设备文件*/
- else if (S_ISBLK(mode)) printf("b");
- /*块设备文件*/
- else if (S_ISFIFO(mode)) printf("p");
- /*管道文件*/
- else if (S_ISLNK(mode)) printf("l");
- /*链接文件*/
- else if (S_ISSOCK(mode)) printf("s");
- /*socket文件*/
- #endif
- }
- void file_power(const struct stat * get_message) {
- mode_t mode = ( * get_message).st_mode & 07777;
- /*取后四位*/
- file_power_char(mode, S_IRUSR, 'r');
- /*判断user有无读权限*/
- file_power_char(mode, S_IWUSR, 'w');
- /*判断user有无写权限*/
- file_power_char(mode, S_IXUSR, 'x');
- /*判断user有无可执行权限*/
- file_power_char(mode, S_IRGRP, 'r');
- /*判断group有无读权限*/
- file_power_char(mode, S_IWGRP, 'w');
- /*判断group有无写权限*/
- file_power_char(mode, S_IXGRP, 'x');
- /*判断group有无可执行权限*/
- file_power_char(mode, S_IROTH, 'r');
- /*判断other有无读权限*/
- file_power_char(mode, S_IWOTH, 'w');
- /*判断other有无写权限*/
- file_power_char(mode, S_IXOTH, 'x');
- /*判断other有无可执行权限*/
- printf(" ");
- }
- void file_power_char(mode_t mode, mode_t type, const char ch) {
- if ((mode & type) == type) printf("%c", ch);
- else printf("-");
- }
- void id_to_string(const struct stat * get_message) {
- struct passwd * pwd;
- /*根据用户id获取用户名*/
- pwd = getpwuid(get_message - >st_uid);
- printf("%s ", pwd - >pw_name);
- struct group * grp;
- /*根据组id获取组名*/
- grp = getgrgid(get_message - >st_gid);
- printf("%s ", grp - >gr_name);
- }
- void timet_to_tm(const struct stat * get_message) {
- struct tm * chtm = localtime( & (get_message - >st_mtime));
- if (chtm == NULL) {
- printf("localtime is error");
- exit(EXIT_FAILURE);
- } else printf("%d月 %d ", chtm - >tm_mon + 1, chtm - >tm_mday);
- /*tm_mon属于[0,11]*/
- if (chtm - >tm_hour < 10)
- /*0~9的数要写成0X格式*/
- printf("0");
- /*先打印0*/
- printf("%d:", chtm - >tm_hour);
- /*再打印X*/
- if (chtm - >tm_min < 10) printf("0");
- printf("%d ", chtm - >tm_min);
- }
- /**
- *filename:main.c
- * 函数功能:ls -l pathname
- * 时间:2017/1/24--19时05分57秒
- * 局限性:不能模糊匹配,不能使用正则,且只能判断普通文件(-)与目录(d)
- * */
- #include int main(char argc, char * *argv) {
- if (argc != 3) {
- printf("Too few parameter!");
- exit(EXIT_FAILURE);
- }
- if ((argc == 3) && !(strcmp(argv[1], "-l"))) {
- /*判断是myls -l argv[2]格式*/
- struct stat get_message = {};
- int ret_stat = stat(argv[2], &get_message);
- if (ret_stat == -1) error("stat %s", argv[2]);
- if (S_ISDIR(get_message.st_mode))
- /*判断是否是目录,是目录则进一步处理目录中个文件*/
- mylist_dir(argv[2]);
- else
- /*不是目录则直接处理普通文件*/
- list_message(argv[2], &get_message);
- /*文件stat信息输出函数*/
- } else {
- /*不符合格式则结束进程*/
- printf("error in main!\n");
- exit(EXIT_FAILURE);
- }
- return 0;
- }
来源: