刚开始写my_ls很没有头绪,因为对一些函数都很陌生,看过就又忘了,所以刚开始,就是照着Linux_c文件操作后面的例子抄的,然后通过函数之间的调用,慢慢的读代码,然后最后有了思路之后,就自己重新写了一个.
首先ls中主要就是应用了Linux文件操作的相关知识.
获取目录信息的函数
(1).opendir函数 ----------->用来打开参数name指定的目录
函数所需头文件:
#include<sys/types.h>
#include<dirent.h>
函数原型:
DIR *opendir(const char *name);
*返回DIR 形态的目录流 ------>类似于FILE文件描述符
失败返回NULL
(2).readdir函数 ------------>用来从参数dir所指向的目录中读取出目录项的信息
函数所需头文件:
#include<sys/types.h>
#include<dirent.h>
函数原型:
struct dirent *readdir(DIR *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 文件名长 */ char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */ }
第一次调用返回该目录下第一个文件信息,直到NULL
(3).closedir函数 -------------->用来关闭参数dir指向的目录
函数所需头文件:
#include<sys/types.h>
#include<dirent.h>
函数原型:
int closedir(DIR* dir);
返回值: 成功 0 错误 -1
对文件的操作主要函数:
函数所在头文件:
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
函数功能:用来获取linux操作系统下文件的属性。
函数原型:
int stat(const char *pathname,struct stat *buf);
struct stat {
dev_t st_dev; 文件的设备编号
ino_t st_ino; 节点
mode_t st_mode; 文件的类型和权限
nlink_t st_nlink; 连到该文件的硬链接数目,刚建立的文件值为1
uid_t st_uid; 用户ID
gid_t st_gid; 组ID
dev_t st_rdev; 设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; 文件字节数(文件大小)
blksize_t st_blksize; 块大小(文件I/O缓冲区的大小)
blkcnt_t st_blocks; 块数
time_t st_atime; 最后一次访问时间
time_t st_mtime; 最后一次修改时间
time_t st_ctime; 最后一次改变时间(指属性) };
但是在写ls的时候,用的函数是lstat,lstat函数对于链接文件是可以追述到源文件的
注意stat与lstat的区别:
stat碰到链接,会追述到源文件,穿透!!lstat并不会穿透。
其实对于-a,-l的实现并不是太难,主要是-R,刚开始想的是,把根目录下的所有目录名都存储起来,然后根据-l,-a那样把每个目录进行处理,这我居然都直接开始上手了,简直是个憨憨,后来一想,连个路径名都不全,怎么可能读到目录中的目录呢?
........
最后就重新换了一种思路,用的递归的写法,目录名不存储了,每次遇到一个就直接进行处理,这块的bug真的是把人搞崩溃了,gdb调试一下午,不是malloc有错,就是free出现了问题,现在终于体会到c语言老师当时说的,有的人malloc和free在实际些东西的时候就会不知道何时进行对应的处理.心累 但是还是有趣的
对于目录的操作和读取里面的内容,一定不能憨憨的用相对路径.
对于-l的写法,我们就要用到 struct stat结构体,从而得到文件的权限与属性,还有时间的操作,我是在网上学的这种处理方法
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 /
int tm_wday; / Day of the week (0-6, Sunday = 0) /
int tm_yday; / Day in the year (0-365, 1 Jan = 0) /
int tm_isdst; / Daylight saving time */ };
//时间处理
struct tm *filetm = localtime(&file.st_mtim .tv_sec);
char timebuf[20];
memset(timebuf,'\0',sizeof(timebuf));
sprintf(timebuf,"%2d月 %2d %02d:%02d",filetm->tm_mon+1 ,filetm->tm_mday,filetm->tm_hour,filetm->tm_min);
对于信号的屏蔽,就要了解未决信号集,阻塞信号集,已经相关的操作函数,在这里先提到这里了,后续会有专门对于信号的博客的.
总之,还是要在应用中学习,刚开始看的天花乱坠的Linux_c编程实战这本书,现在经过不断的练习,倒也不那么难搞了.
最后附上写的代码:https://github.com/hchc32/TeamC/blob/master/hc/pratice/Linux_c/My_Ls.c