一、使用ls -l 以排序方式输出目录信息
1.需求以及知识点覆盖
ls -l 命令根据后面的参数将列出某文件即目录下的基本信息。
如果没有具体的目录或者文件,则列出当前目录下所有的非隐藏文件的信息,包括文件类型,文件权限,硬链接个数,拥有者。拥有者所在组,文件大小,文件更新时间等。
such as :
若没有指定的文件,则输出所有目录下的文件信息:
所以,本应用要实现的基本功能和需要的知识点有:
①参数检查。包括参数个数检查,如果有多个需要列出信息的文件及目录,则遍历所有的参数,另外需要读取当前参数是文件还是目录。(stat函数可以读取)
②如果是普通文件,需要构建此文件的链表,然后使用stat()函数读取链表成员文件的属性,并根据stat输出结果进行用户ID到用户名的转化,组id到组名的转换,以及时间的转换(stat函数的时间是linux时间,1970-1-1至此刻的秒数)。
③如果是目录文件,需要一次读取该目录先的文件列表,并按需存储在链表中,本示例中选用简单的插入排序,然后读取该文件的基本信息。
2.流程
主函数流程如下:
①参数检查。参数不能少于两个,如果参数大于两个,列出对应的信息。
②检测参数类型,如果是普通文件且存在,则读取该文件的属性。
③如果是目录文件,循环查找目录下的所有文件,采用及简单的插入排序读取信息,并列出整个链表文件信息。
3.代码实现
具体代码如下,详细过程那个见注释。
/************************************************************************* > File Name: sort_l.c > Author: SuooL > Mail: [email protected] > Created Time: 2014年07月31日 星期五 15时44分32秒 ************************************************************************/ #include<stdio.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #include<sys/stat.h> #include<time.h> #include<pwd.h> #include<grp.h> #define NAME_SIZE 256 // 构建的链表节点数据结构 struct fnode { struct fnode *next; // 下一个成员 char name[NAME_SIZE]; // 当前成员文件名 }; struct fnode *insert_list(struct fnode *temp,struct fnode *head) { if(head==NULL) //if linklist is empty,for temp is the first one { head=temp; return head; } if(strcmp(temp->name,head->name)<0) //temp will be insert before first one { temp->next=head; head=temp; return head; } struct fnode *next=head->next; struct fnode *prev=head; while(next!=NULL&& strcmp(temp->name,next->name)>0) { next=next->next; prev=prev->next; } temp->next=next; prev->next=temp; return head; } // 读取文件权限属性函数,根绝参数(lstat函数返回类型st_mode)列出各个文件的权限个类型字符 output_type_perm(mode_t mode) { char type[7]={'p','c','d','b','-','l','s'}; int index=((mode>>12) & 0xF)/2; printf("%c",type[index]); char *perm[8]={"---","--x","-w-","-wx","r--","r-x","rw-","rwx"};//rwx printf("%s",perm[mode>>6 &07]); printf("%s",perm[mode>>3 &07]); printf("%s",perm[mode>>0 &07]); } // 列出用户及组 void output_user_group(uid_t uid,gid_t gid) { struct passwd *user; user=getpwuid(uid); printf(" %s",user->pw_name); struct group *group; group=getgrgid(gid); printf(" %s",group->gr_name); } // 列出个文件基本信息函数将各个函数的返回值输出的屏幕 output_mtime(time_t mytime) { char buf[256]; memset(buf,'\0',256); ctime_r(&mytime,buf); buf[strlen(buf)-1]='\0'; //memcpy(buf,ctime(mytime),strlen(ctime(mytime))-1); printf(" %s",buf); } void output_info(struct fnode *head) { struct fnode *temp=head; while(temp!=NULL) { struct stat mystat; if(-1==stat(temp->name,&mystat)) { perror("stat");exit(EXIT_FAILURE); } output_type_perm(mystat.st_mode); printf(" %4d",mystat.st_nlink); output_user_group(mystat.st_uid,mystat.st_gid); printf(" %8ld",mystat.st_size); output_mtime(mystat.st_mtime); printf(" %s\n",temp->name); temp=temp->next; } } void free_list(struct fnode *ptr) { struct fnode *temp=ptr; struct fnode *link=ptr; while(ptr) { temp=ptr; ptr=ptr->next; free(temp); } } // main()函数源码 int main(int argc,char *argv[]) { if(argc < 2) { printf("usage :%s dir_name\n",argv[0]);exit(EXIT_FAILURE); } int i; for(i=1;i<argc;i++) { struct fnode *linklist=NULL; struct stat stat_info; if(stat(argv[i],&stat_info)==-1) { perror("stat");exit(EXIT_FAILURE); } if (S_ISREG(stat_info.st_mode)) //regular file { struct fnode *temp=(struct fnode *)malloc(sizeof(struct fnode)); if(NULL==temp) { perror("malloc");exit(EXIT_FAILURE); } temp->next=NULL; memset(temp->name,'\0',NAME_SIZE); memcpy(temp->name,argv[i],strlen(argv[i])); linklist=insert_list(temp,linklist); output_info(linklist);//output information of the file } else if(S_ISDIR(stat_info.st_mode)) { char buf[NAME_SIZE]; getcwd(buf,128); DIR *dirp=NULL; dirp=opendir(argv[i]); if(NULL==dirp) { perror("opendir");exit(EXIT_FAILURE); } struct dirent *entp=NULL; while(entp=readdir(dirp)) { struct fnode *temp=(struct fnode *)malloc(sizeof(struct fnode)); if(NULL==temp) { perror("malloc");exit(EXIT_FAILURE); } temp->next=NULL; memset(temp->name,'\0',NAME_SIZE); memcpy(temp->name,entp->d_name,strlen(entp->d_name)); linklist=insert_list(temp,linklist); } chdir(argv[i]);//change the current dirctory close(dirp); output_info(linklist); chdir(buf); } free_list(linklist); } return 1; }
运行结果:
二、实现tree系统命令
1.问题分析
linux中的tree命令可以实现以树形结构列出某个指定目录下的所有问价以及目录名,如下所示的效果:
我们就要实现这样一个tree命令。基本的流程如下:
(1)系统初始化。构建一个空队列,该队列将实时缓存整个目录(含有子目录)中未输出的文件呢信息。
(2)读取目录下所有的文件信息以及目录信息,按照ASCII码值的大小构建一个新的子排序队列。
(3)将子队列与整个目录的队列合并,采用的方法类似于栈的操作,即将整个子队列加到原来的队列的前面,更新全局队列的信息。
(4)出队列。读取队列的第一个成员的属性。如果是一个文件,直接按信息输出,如果是一个目录,重复上面的(2)(3)(4)步骤。递归循环操作。
2.程序流程图
3.代码
关于递归部分,类似与之前写的递归复制目录文件的应用小程序。
<pre name="code" class="cpp">#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <dirent.h> #include <fcntl.h> #include <errno.h> #define REGU_FILE 1 #define DIR_FILE 2 // 构建栈式结构中每个节点代表一个文件,节点数据结构定义如下: typedef struct node { struct node *next; // 下一个节点,构建单链结构 unsigned int level; // 当前子目录的深度,用于区分输出时的层次 char *name; // 所在的目录下的文件名,不含有上级目录,用于输出名字 char *fullname; // 输出整个路径名,用于读取属性 }filenode; // 队列数据结构 typedef struct head { struct node *head; // 队首指针 struct node *rear; // 队尾指针 }headnode; void dir_tree(char *dirname,headnode *link_stack, int level); int insert_sort(headnode *link_stack, filenode *NEW) { filenode *next = link_stack->head; filenode *prev = NULL; while(next) { if (strcmp( NEW->name, next->name ) > 0 ) { prev = next; next = next->next; } else break; } if(link_stack->head == NULL && link_stack->rear == NULL) //the first one { link_stack->head = NEW; link_stack->rear = NEW; } else if(prev == NULL && next != NULL) //insert in front of the queue { NEW->next = link_stack->head; link_stack->head = NEW; } else if( prev != NULL && next == NULL) //insert in end of the queue. { prev->next = NEW; link_stack->rear = NEW; } else { prev->next = NEW; NEW->next = next; } } headnode *read_dir_to_link_stack(char *dir,int level) { DIR *dirp = NULL; if(NULL== (dirp=opendir(dir))) { perror("opendir");exit(EXIT_FAILURE); } headnode *ptr = (headnode *)malloc (sizeof (headnode)); if(ptr==NULL) { perror("malloc");exit(EXIT_FAILURE); } ptr->head = NULL; ptr->rear = NULL; struct dirent *entp = NULL; while ( NULL != (entp =readdir(dirp))) { if (strcmp(entp->d_name, "..")==0 || strcmp(entp->d_name, ".")==0) //ignore ./ ../ { continue; } else { filenode *temp = (filenode *)malloc(sizeof(filenode)); if(temp==NULL) { perror("malloc");exit(EXIT_FAILURE); } temp->next = NULL; temp->level = level; temp->name = (char *)malloc(strlen( entp->d_name) + 1); sprintf(temp->name ,"%s\0", entp->d_name); temp->fullname = (char *)malloc(strlen(dir)+1+strlen( entp->d_name) + 1); sprintf(temp->fullname,"%s/%s\0",dir,entp->d_name); insert_sort(ptr,temp); } } closedir(dirp); return ptr; } /* type:1, regufile. 2 dir. */ // 输出某个文件的信息格式 void out_file_info(filenode *ptr, int type) { int i; printf("|"); for(i = 0;i < ptr->level; i++) { printf(" "); } printf("|-- "); printf("%s\n",ptr->name); } void pop_file_tree(headnode *link_stack) { while(link_stack->head != NULL ) // 遍历所有节点 { struct stat stat_src; if (lstat(link_stack->head->fullname, &stat_src) != 0) { fprintf(stderr, "%s(%d): stat error(%s)!\n", __FILE__, __LINE__, strerror(errno)); } if(S_ISDIR(stat_src.st_mode)) // 目录,调用dir_tree函数 { filenode *temp = link_stack->head; link_stack->head = link_stack->head->next; if(link_stack->head == NULL) link_stack->rear ==NULL; out_file_info(temp,DIR_FILE); dir_tree(temp->fullname,link_stack,temp->level); free(temp->name); free(temp->fullname); free(temp); } else // 否则输出文件 { filenode *temp = link_stack->head; link_stack->head = link_stack->head->next; if(link_stack->head == NULL) link_stack->rear ==NULL; out_file_info(temp,REGU_FILE); free(temp->name); free(temp->fullname); free(temp); } } } // 输出目录和子目录信息递归函数 void dir_tree(char *dirname,headnode *link_stack, int level) { headnode *ret = NULL; // 读取目录信息,返回一个排序队列,队列中每个节点包括子文件的文件名和整个路径 ret = read_dir_to_link_stack(dirname, level+1); // 将原队列与新的返回队列合并,将新的返回队列放到原队列前,类似于栈操作 if(link_stack->head != NULL && ret->head != NULL) { ret->rear->next = link_stack->head; link_stack->head = ret->head; } if(link_stack->head == NULL && ret->head != NULL ) link_stack->head = ret->head; if(link_stack->rear == NULL && ret->rear != NULL) link_stack->rear = ret->rear; free(ret); pop_file_tree(link_stack); } int main(int argc,char *argv[]) { if (argc != 2 ) // 如果没有给定目录 { fprintf(stderr,"pls useage %s dir_name\n",argv[0]);exit(EXIT_FAILURE); } struct stat stat_src; if (lstat(argv[1], &stat_src) != 0) // 读取文件属性 { fprintf(stderr, "%s(%d): stat error(%s)!\n", __FILE__, __LINE__, strerror(errno)); exit(EXIT_FAILURE); } if (S_ISREG(stat_src.st_mode)) //regular file,报错 { fprintf(stderr, "%s [error opening dir]\n",argv[1]);exit(EXIT_FAILURE); } else if(S_ISDIR(stat_src.st_mode)) // 目录文件 { headnode *link_stack = (headnode *)malloc (sizeof (headnode)); if(link_stack == NULL) { perror("malloc");exit(EXIT_FAILURE); } link_stack->head = NULL; // 初始化全局队列 link_stack->rear = NULL; printf("%s\n",argv[1]); dir_tree(argv[1], link_stack,-1); // 执行函数 free(link_stack); // 完毕,回收内存 } else return 1; }
运行结果:
Next
终端及串口编程
Linux进程管理与程序开发
Linux 程序设计学习笔记----文件管理实例应用