姓名:傅伟杰
学号:201821121018
班级:计算1811
1. 编写程序
在服务器上用Vim编写一个程序:实现Linux系统命令ls -lai
的功能,给出源代码。
源代码:
lab4.c #include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<grp.h> #include<pwd.h> #include<dirent.h> void myls(char []); void do_stat(char *); void print_myinfo(char *,struct stat *); void mode_to_type(int mode,char buf[]); char *uid_to_name(uid_t uid); char *gid_to_name(gid_t gid); void myls(char dir[]) { DIR *pathdir = opendir(dir);//获取路径 struct dirent *pd = NULL; if(pathdir == NULL)//路径为空 { fprintf(stderr,"open dir is error!\n"); } else//路径不为空 { while((pd = readdir(pathdir)) != NULL) /*一次读取目录中的下一个文件,直到读完*/ { do_stat(pd->d_name); } closedir(pathdir); /*关闭pathdir指向的目录流*/ } } void do_stat(char *file) { struct stat myinfo; if(stat(file,&myinfo) == -1) { perror(file);//出错情况,输出文件名 } else { print_myinfo(file,&myinfo); } } void print_myinfo(char *file,struct stat* p_myinfo) { char *uid_to_name(),*ctime(),*gid_to_name(); void mode_to_type(); char str[11]; mode_to_type(p_myinfo->st_mode,str); printf("%d ",(int)p_myinfo->st_ino); printf("%s",str); printf("%4d ",(int)p_myinfo->st_nlink); printf("%-8s ",uid_to_name(p_myinfo->st_uid)); printf("%-8s ",gid_to_name(p_myinfo->st_gid)); printf("%8ld ",(long)p_myinfo->st_size); printf("%.12s ",4 + ctime(&p_myinfo->st_mtime)); printf("%s\n",file); } void mode_to_type(int md,char mode[]) { strcpy(mode,"-----------"); if(S_ISCHR(md)) mode[0] = 'c'; if(S_ISDIR(md)) mode[0] = 'd'; if(S_ISBLK(md)) mode[0] = 'b'; if(md & S_IRUSR) mode[1] = 'r'; if(md & S_IWUSR) mode[2] = 'w'; if(md & S_IXUSR) mode[3] = 'x'; if(md & S_IRGRP) mode[4] = 'r'; if(md & S_IWGRP) mode[5] = 'w'; if(md & S_IXGRP) mode[6] = 'x'; if(md & S_IROTH) mode[7] = 'r'; if(md & S_IWOTH) mode[8] = 'w'; if(md & S_IXOTH) mode[9] = 'x'; } char *uid_to_name(uid_t uid) { struct passwd * getpwuid(),*pw_ptr; static char str[10]; if((pw_ptr = getpwuid(uid)) == NULL) { sprintf(str,"%d",uid); return str; } else { return pw_ptr->pw_name; } } char *gid_to_name(gid_t gid) { struct group * getgrgid(),*grp_ptr; static char str[10]; if((grp_ptr = getgrgid(gid)) == NULL) { sprintf(str,"%d",gid); return str; } else { return grp_ptr->gr_name; } } int main(int argc,char **argv) { if(argc == 1) { myls("."); } else { while(--argc) { printf("%s:\n",*++argv); myls(*argv); } } return 0; }
2. 分析运行结果
给出运行结果截图,对于每一列是如何获取的,结合源代码做解释
下面先给出系统ls -lai 的截图:
运行编写的c程序得到的数据的截图:
首先先进行ls指令的具体分析:
下面给出一些较为常见的参数,并解释参数的意义
-a 显示所有文件及目录 (ls内定将文件名或目录名称开头为"."的视为隐藏档,不会列出) -l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出 -r 将文件以相反次序显示(原定依英文字母次序)-t 将文件依建立时间之先后次序列出 -A 同 -a ,但不列出 "." (目前目录) 及 ".." (父目录) -F 在列出的文件名称后加一符号;例如可执行档则加 "*", 目录则加 "/" -R 若目录下有文件,则以下之文件亦皆依序列出 -i –inode 印出每个文件的 inode 号
在linux中通过ls指令输出的文件名的颜色是有着一定的意义的
默认颜色为普通文件
绿色为可执行文件
红色为tar包文件
蓝色为目录文件
水红色为图像文件
青色为链接文件
黄色为设备文件
具体颜色可参考下图:
我们这一次实验需要实现的时 ls -lai:
首先要做的是获取目录下面的文件名称:
具体实现
函数myls void myls(char dir[]) { DIR *pathdir = opendir(dir);//获取路径 struct dirent *pd = NULL; if(pathdir == NULL)//路径为空 { fprintf(stderr,"open dir is error!\n"); } else//路径不为空 { while((pd = readdir(pathdir)) != NULL) /*一次读取目录中的下一个文件,直到读完*/ { do_stat(pd->d_name); } closedir(pathdir); /*关闭pathdir指向的目录流*/ } }
然后获取文件:
接着解释一下获取某个目录下的某个文件的详细信息的操作
1.首先,通过opendir()函数打开目录,然后返回指向目录的DIR结构体
2.然后,调用readir()函数读取目录下面的索引文件,并返回指向该目录下的所有文件的dirent结构体d
3.最后遍历d,调用stat进行详细信息的获取
具体实现
函数print_myinfo void print_myinfo(char *file,struct stat* p_myinfo) { char *uid_to_name(),*ctime(),*gid_to_name(); void mode_to_type(); char str[11]; mode_to_type(p_myinfo->st_mode,str); printf("%d ",(int)p_myinfo->st_ino); printf("%s",str); printf("%4d ",(int)p_myinfo->st_nlink); printf("%-8s ",uid_to_name(p_myinfo->st_uid)); printf("%-8s ",gid_to_name(p_myinfo->st_gid)); printf("%8ld ",(long)p_myinfo->st_size); printf("%.12s ",4 + ctime(&p_myinfo->st_mtime)); printf("%s\n",file); }
关于stat和dirent的解释
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; //文件字节数(文件大小)**
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间**
time_t st_mtime; //最后一次修改时间**
time_t st_ctime; //最后一次改变时间(指属性)**
**代表本次编写中有使用到的
dirent结构体集具体如下:
long d_ino; //索引号节点号
off_t d_off; //目录中的偏移量
unsigned short d_reclen; //文件长度
char d_name [NAME_MAX+1]; //文件名称
3. 通过该实验产生新的疑问及解答
Question:我编写的程序中相比于系统的ls还是较为简陋的,主要的点在于输出文件的颜色含义并没有对应好,如何对不同的文件类型采取正确的分类?
Answer:具体内容参考了下列网站(见参考资料第二条),了解了关于linux ansi控制码的一些相关信息,发现能够成功解决,只需要在输出的时候判断文件类型,并选择对应的ansi码进行颜色控制即可.
参考资料:
https://www.runoob.com/linux/linux-comm-ls.html
https://blog.csdn.net/daoer_sofu/article/details/102456935
https://www.cnblogs.com/xiaoshiwang/p/10764243.html