改进要求
- 排序:文件名读入数组,利用qsort排序
- 分栏:文件名读入数组,计算列宽和行高
- .和..加入-a选项,没有-a,不显示隐藏文件
- -l:功能不同,单独实现
首先我们来看一下ls -l的具体功能:
可见陈列出了所有输出信息,是用单列格式输出的,不输出为多列
根据要求编写代码
码云链接如下:
https://gitee.com/wang-jingspm/wjls
运行结果:
输入命令./upls -a
在原来的ls -a中,加上-a后显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为隐藏,不会列出)。
输入命令 ./upls -l
可见显示出了所有信息,包括使用者的权限、修改日期、使用者身份等,且都是以列的形式显示的。
代码分析
1.实现排序部分
首先用opendir系统调用打开目录,获取目录下的文件总数,定义一个g_maxlen,在反复赋值替换中获取最长的文件名,其中文件个数最大值设置为256个。
其次获取目录下所有的文件名称。调用dirent结构体,获取文件名称。
这里我们调用了C语言库中的strncpy函数:
char *strncpy(char *dest, const char *src, size_t n)
把src所指向的字符串复制到dest,最多复制n个字符。当src的长度小于n时,dest的剩余部分将用空字节填充。该函数能够返回最终复制后的字符串。代码中的含义即为将path指针所指向的字符串复制到创建的文件夹filename[]里,长度是路径指针所指的文件名字的长度。调用dirent结构体来获取文件名字。
排序即逐个比较文件名的字符大小,较小的放在数组低位置,较大的放置在数组高位置。这里调用了较为简单的排序方法,实现对文件名的排序。
2.实现分栏部分
这里我们定义了一个宏常量int g_leave_len = MAXROWLEN,用于实现输出对齐
3.实现-a -l部分
param[32]是一个保存命令行参数的数组,这里的PARAM_A和PARAM_L的宏定义分别是1和2,用来根据命令行的输入(是a还是l)做选择判断,调用不同的函数实现
这里实现了-l 的功能,获取文件类型,这里调用了stat结构体的内容,输出文件的相关信息:
struct stat {
dev_t st_dev; /* 文件所在设备的标识 */
ino_t st_ino; /* 文件结点号 */
mode_t st_mode; /* 文件保护模式 */
nlink_t st_nlink; /* 硬连接数 */
uid_t st_uid; /* 文件用户标识 */
gid_t st_gid; /* 文件用户组标识 */
dev_t st_rdev; /* 文件所表示的特殊设备文件的设备标识 */
off_t st_size; /* 总大小,单位为字节*/
blksize_t st_blksize; /* 文件系统的块大小 */
blkcnt_t st_blocks; /* 分配给文件的块的数量,512字节为单元 */
time_t st_atime; /* 最后访问时间 */
time_t st_mtime; /* 最后修改时间 */
time_t st_ctime; /* 最后状态改变时间 */
};
我们来判断文件类型,常常使用这几个宏:
- S_ISLNK(st_mode):是否是一个连接.
- S_ISREG(st_mode):是否是一个常规文件.
- S_ISDIR(st_mode):是否是一个目录
- S_ISCHR(st_mode):是否是一个字符设备.
- S_ISBLK(st_mode):是否是一个块设备
- S_ISFIFO(st_mode):是否 是一个FIFO文件.
- S_ISSOCK(st_mode):是否是一个SOCKET文件
我们使用最多的属性是st_mode,如果返回真,代表是目录或者连接等等