仿写ls -l的功能(编写myls程序),参数通过命令行传入:
1、获取当前工作目录路径并对该目录实现遍历
2、仿ls -l以列表形式出当前工作目录下的所有文件(包括子目录)
需显示的文件属性有:
文件类型 权限 硬链接数 所有者用户名 所有者所在组用户名 文件大小 最后修改时间
1.获取当前工作路径
头文件:unistd.h
函数:*char get_current_dir_name();
成功返回路径字符串缓冲区指针(该内存区需要手动释放),
失败返回NULL
2.打开关闭目录函数
头文件:dirent.h
函数:DIR * opendir(const char * name);
打开name指定的目录,并关联一个目录流(类似于C库函数中的文件流),失败返回NULL
函数:int closedir(DIR *dir);
关闭指定目录流,释放相关数据结构。成功返回0;失败返回-1
3.读取目录文件函数
头文件:sys/types.h; dirent.h
函数:*struct dirent * readdir(DIR dir);
读取目录流dir标识的目录下文件,到达文件结尾或者错误发生,返回NULL
4.获取文件信息
头文件:sys/stat.h
函数:
*int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat buf);
读取path参数指定文件的文件属性,填充到buf参数指向的结
构体。lstat返回符号链接(快捷方式)的文件属性,stat返回符号链接引用文件(源头文件)的文件属性
5.1 获取用户属性函数
头文件:sys/types.h;pwd.h
函数:*struct passwd getpwuid(uid_t uid);
输入用户ID,返回用户属性信息(passwd结构)
5.2 获取用户组属性函数
头文件:sys/types.h;grp.h
函数:*struct group getgrgid(gid_t gid);
输入用户组ID,返回用户组属性信息(group结构)
6.获取文件时间信息
头文件:time.h
函数:char ctime(const time_t timep);
ctime直接解析为当地时间格式例如“wed jun 30 21:49:08 1993\n”
源程序:
#include<unistd.h>
#include<dirent.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pwd.h>
#include<grp.h>
#include<iostream>
using namespace std;
void print_type(mode_t st_mode);//判断并输出文件类型
void print_perm(mode_t st_mode);//判断并输出文件权限
void print_link(nlink_t st_nlink);//输出文件硬链接数
void print_usr_name(uid_t st_uid);//输出文件所有者
void print_group_name(gid_t st_gid);//输出用户组名
void print_file_size(off_t st_size);//输出文件大小
void print_time(time_t st_time);//输出最后一次修改时间
void print_file_name(char *file_name);//输出文件名
int main(int argc, char *argv[]){
/*
if(argc != 3){
printf("argc=%d\t命令错误,请重试!!\n",argc);
return -1;
}
printf("test1:\t参数1:%s\t参数2:%s\n",argv[1],argv[2]);
if(strcmp(argv[2],"-l"|"-s") == 0){
printf("true,-l\n");
}
*/
/*
for(int i = 0; i < argc; i++ ){
printf("argv[%d]=%s\n",i,argv[i]);
}*/
/*
--help 解释文档
-l l,即List,列表。 展示文件详细信息
-c c,即Catalog,目录。 展示目录本身“.”和上级目录“..”
-a a,即All,全部。 展示隐藏文件(以.开头)
-p p,即Property,属性 展示符号链接的文件属性 ,默认是返回符号链接引用文件的文件属性
*/
int ls_flag, help_flag, l_flag, c_flag, a_flag, p_flag;
ls_flag = help_flag = l_flag = c_flag = a_flag = p_flag = 0;
if(strcmp(argv[1],"ls") == 0){//主命令
ls_flag = 1;
}
for(int i = 2; i < argc; i++ ){
if(strcmp(argv[i],"--help") == 0){
help_flag = 1;
}
if(strcmp(argv[i],"-l") == 0){
l_flag = 1;
}
if(strcmp(argv[i],"-c") == 0){
c_flag = 1;
}
if(strcmp(argv[i],"-a") == 0){
a_flag = 1;
}
if(strcmp(argv[i],"-p") == 0){
p_flag = 1;
}
}
//printf("test12:\t参数判断:ls_flag=%d help_flag=%d l_flag=%d c_flag=%d a_flag=%d p_flag=%d\n",ls_flag,help_flag,l_flag,c_flag,a_flag,p_flag);
//①ls --help
if(help_flag == 1 && argc == 3){
cout<<"myls程序帮助文档:"<<endl;
cout<<"-l\tl,即List,列表。\t展示文件详细信息"<<endl;
cout<<"-c\tc,即Catalog,目录。\t展示目录本身“.”和上级目录“..”"<<endl;
cout<<"-a\ta,即All,全部。\t展示隐藏文件(以.开头)"<<endl;
cout<<"-p\tp,即Property,属性\t展示符号链接引用文件的文件属性,默认是返回符号链接的文件属性"<<endl;
exit(0);
}
/*
else{//ls --help之后存在参数,报错
printf("命令错误,正确帮助命令为:ls --help\n");
exit(-1);
}*/
//获取当前工作目录
char * current_dir_name = NULL;
current_dir_name = get_current_dir_name();
//printf("test2:\t当前目录:%s\n",current_dir_name);
//打开当前工作目录
DIR * current_dir = NULL;//目录文件类型
struct dirent * current_dp = NULL;//
struct stat current_stat;//获取文件信息
if((current_dir = opendir(current_dir_name)) == NULL){
printf("打开目录失败,请重试\n");
return -1;
}
else{
//printf("目录下包含的文件是:\n");
while((current_dp = readdir(current_dir)) != NULL){
if(ls_flag == 1){//ls主命令存在
if(argc == 2){//仅仅是命令ls
//②ls
if(current_dp->d_name[0] != '.'){//排除一二级目录文件和隐藏文件
printf("%s\t",current_dp->d_name);
}
}
else{//除命令ls外,其后还有其他参数
if(l_flag == 0 && c_flag == 1 && a_flag == 0){//ls -c
if(current_dp->d_name[0] != '.' || strcmp(current_dp->d_name,".") == 0 || strcmp(current_dp->d_name,"..") == 0){
printf("%s\t",current_dp->d_name);
}
}
else if(l_flag == 0 && a_flag == 1){//ls -a (-c/-p)
printf("%s\t",current_dp->d_name);
}
else if(l_flag == 0){//ls -p
if(current_dp->d_name[0] != '.'){//排除一二级目录文件和隐藏文件
printf("%s\t",current_dp->d_name);
}
}
else if(l_flag == 1 && c_flag == 0 && a_flag == 0){//*******③ls -l (-p)
//printf("test3:\t文件名:%s\n",current_dp->d_name);
if(current_dp->d_name[0] != '.'){//排除一二级目录文件和隐藏文件
//if((stat(current_dp->d_name,¤t_stat)) == -1 ){
if((p_flag == 1)?((stat(current_dp->d_name,¤t_stat)) == -1):((lstat(current_dp->d_name,¤t_stat)) == -1)){
//判断p_flag是否为1,若为1则使用stat函数
printf("获取文件(%s)详细信息失败\n",current_dp->d_name);
continue;
}
else{
print_type(current_stat.st_mode);
print_perm(current_stat.st_mode);
print_link(current_stat.st_nlink);
print_usr_name(current_stat.st_uid);
print_group_name(current_stat.st_gid);
print_file_size(current_stat.st_size);
print_time(current_stat.st_mtime);
print_file_name(current_dp->d_name);
}
}
}
else if(l_flag == 1 && c_flag == 1 && a_flag == 0){//*******④ls -l -c (-p)
if(current_dp->d_name[0] != '.' || strcmp(current_dp->d_name,".") == 0 || strcmp(current_dp->d_name,"..") == 0){//包括当前目录“.”和上级目录“..”,排除其他.隐藏文件
//if((stat(current_dp->d_name,¤t_stat)) == -1 ){
if((p_flag == 1)?((stat(current_dp->d_name,¤t_stat)) == -1):((lstat(current_dp->d_name,¤t_stat)) == -1)){
//判断p_flag是否为1,若为1则使用stat函数
printf("获取文件(%s)详细信息失败\n",current_dp->d_name);
continue;
}
else{
print_type(current_stat.st_mode);
print_perm(current_stat.st_mode);
print_link(current_stat.st_nlink);
print_usr_name(current_stat.st_uid);
print_group_name(current_stat.st_gid);
print_file_size(current_stat.st_size);
print_time(current_stat.st_mtime);
print_file_name(current_dp->d_name);
}
}
}
else if(l_flag == 1 && a_flag == 1){
//包括当前目录“.”和上级目录“..”,排除其他.隐藏文件
//if((stat(current_dp->d_name,¤t_stat)) == -1 ){
if((p_flag == 1)?((stat(current_dp->d_name,¤t_stat)) == -1):((lstat(current_dp->d_name,¤t_stat)) == -1)){
//判断p_flag是否为1,若为1则使用stat函数
printf("获取文件(%s)详细信息失败\n",current_dp->d_name);
continue;
}
else{
print_type(current_stat.st_mode);
print_perm(current_stat.st_mode);
print_link(current_stat.st_nlink);
print_usr_name(current_stat.st_uid);
print_group_name(current_stat.st_gid);
print_file_size(current_stat.st_size);
print_time(current_stat.st_mtime);
print_file_name(current_dp->d_name);
}
}
}
}
else{//ls不存在,报错
printf("命令错误,请重试\n");
exit(-1);
}
}
if(l_flag == 0){
cout<<endl;//回车更美观
}
closedir(current_dir);
}
free(current_dir_name);//手动释放缓存
return 0;
}
void print_type(mode_t st_mode){
char * ptr = NULL;
if(S_ISREG(st_mode)) ptr = "-";//- 普通文件
else if(S_ISDIR(st_mode)) ptr = "d";//d 目录文件
else if(S_ISCHR(st_mode)) ptr = "c";//c 字符设备文件
else if(S_ISBLK(st_mode)) ptr = "b";//b 块设备文件
else if(S_ISFIFO(st_mode)) ptr = "p";//p 管道或FIFO
else if(S_ISLNK(st_mode)) ptr = "l";//l 符号链接
else if(S_ISSOCK(st_mode)) ptr = "s";//s 套接字
else ptr = " ";
//printf("test4:\t文件类型=%s\n",ptr);
printf("%s",ptr);
}
void print_perm(mode_t st_mode){//r读 w写 x执行
char ptr[10];
//判断文件所有者权限
if((S_IRUSR&st_mode) == S_IRUSR) strcat(ptr,"r");
else strcat(ptr,"-");
if((S_IWUSR&st_mode) == S_IWUSR) strcat(ptr,"w");
else strcat(ptr,"-");
if((S_IXUSR&st_mode) == S_IXUSR) strcat(ptr,"x");
else strcat(ptr,"-");
//判断用户组权限
if((S_IRGRP&st_mode) == S_IRGRP) strcat(ptr,"r");
else strcat(ptr,"-");
if((S_IWGRP&st_mode) == S_IWGRP) strcat(ptr,"w");
else strcat(ptr,"-");
if((S_IXGRP&st_mode) == S_IXGRP) strcat(ptr,"x");
else strcat(ptr,"-");
//判断其他用户权限
if((S_IROTH&st_mode) == S_IROTH) strcat(ptr,"r");
else strcat(ptr,"-");
if((S_IWOTH&st_mode) == S_IWOTH) strcat(ptr,"w");
else strcat(ptr,"-");
if((S_IXOTH&st_mode) == S_IXOTH) strcat(ptr,"x");
else strcat(ptr,"-");
//printf("test5:\t文件权限=%s\n",ptr);
printf("%s",ptr);
}
void print_link(nlink_t st_nlink){
//printf("test6:\t硬链接数=%d\n",st_nlink);
printf(" %d",st_nlink);
}
void print_usr_name(uid_t st_uid){
struct passwd *current_passwd = NULL;//passwd结构
current_passwd = getpwuid(st_uid);
//printf("test7:\t文件所有者=%s\n",current_passwd->pw_name);
printf("\t%s",current_passwd->pw_name);
}
void print_group_name(gid_t st_gid){
struct group *current_group = NULL;//group结构
current_group = getgrgid(st_gid);
//printf("test8:\t用户组=%s\n",current_group->gr_name);
printf("\t%s",current_group->gr_name);
}
void print_file_size(off_t st_size){
//printf("test9:\t文件大小=%ld\n",st_size);
printf("\t%ld",st_size);
}
void print_time(time_t st_time){
struct tm *current_tm = NULL;
current_tm= localtime(&st_time);
//printf("test10:\t最后一次修改时间=%d-%d-%d %d:%d:%d\n",current_tm->tm_year+1900, current_tm->tm_mon+1, current_tm->tm_mday, current_tm->tm_hour, current_tm->tm_min, current_tm->tm_sec);
printf("\t%d-%d-%d %d:%d:%d",current_tm->tm_year+1900, current_tm->tm_mon+1, current_tm->tm_mday, current_tm->tm_hour, current_tm->tm_min, current_tm->tm_sec);
}
void print_file_name(char *file_name){
//printf("test11:\t文件大小=%s\n",file_name);
printf(" \t%s\n",file_name);
}