UNIX程序设计实验三 目录树的遍历

时间:2022-11-02 12:33:43

                                                              实验三 目录树的遍历

                                                                                         

一、目的   

掌握与文件和目录树有关的系统调用和库函数。

二、要求

1、编写程序myfind

命令语法:myfind  <pathname>  [-comp <filename> | -name <str>…]

命令语义:

(1)myfind  <pathname> 的功能:

     除了具有与程序4-7相同的功能外,还要输出在<pathname>目录子树之下,文件长度不大于4096字节的常规文件,在所有允许访问的普通文件中所占的百分比。程序不允许打印出何路径名。

(2)myfind  <pathname>  -comp <filename>的功能:

     <filename>是常规文件的路径名(非目录名,但是其路径可以包含目录)。命令仅仅输出在<pathname>目录子树之下,所有与<filename>文件内容一致的文件的绝对路径名。不允许输出任何其它的路径名,包括不可访问的路径名。

(3)myfind  <pathname>  -name <str>…的功能:

<str>…是一个以空格分隔的文件名序列(不带路径)。命令输出在<pathname>目录子树之下,所有与<str>…序列中文件名相同的文件的绝对路径名。不允许输出不可访问的或无关的路径名。 <pathname>和<filename>均既可以是绝对路径名,也可以是相对路径名。<pathname>既可以是目录,也可以是文件,此时,目录为当前工作目录。

2、注意尽可能地提高程序的效率。注意避免因打开太多文件而产生的错误。

3、遍历目录树时,访问结点(目录项)的具体操作应当由遍历函数dopath携带的函数指针参数决定。这样程序的结构清晰,可扩充性好。

 

三、设计和实现的主要原理、构思、算法

#include"apue.h"

#include<dirent.h>

#include<limits.h>

#include<sys/stat.h>

#include<string.h>

#include<malloc.h>

#include<fcntl.h>

char*path_alloc(int * size)//定义path_alloc()这个函数,path_alloc函数主要是为路径(完整路径)分配内存空间

{

char*p=NULL;

if(!size)return NULL;

p=malloc(256);

if(p)

*size=256;

else

*size=0;

returnp;

}

 

 

typedefint Myfunc(const char*,const struct stat *,int);//声明了一个新的函数类型Myfunc,这种函数类型带3个参数,返回值是int类型的

staticMyfunc myfunc1,myfunc2,myfunc3;//声明了三个对象

staticint myftw(char *,Myfunc *);//声明函数myftw的原形,其参数两个,其一为一指针,其二为一函数名

staticint dopath(Myfunc *);//dopath函数,主要是通过递归获取路径,并判断是目录还是文件,从而转向myfunc函数进一步判断并计数

staticlong nreg,ndir,nblk,nchr,nfifo,nslink,nsock,ntot,size,dsize,count;//全局变量,ntot是表示文件的总数

staticchar *dbuf,*filename;

int

main(intargc,char *argv[])//主函数

{

       int ret,fd,i;

       struct stat buf;

       if(strcmp(argv[0],"./myfind")!=0)err_ret("Input error.\n");

       if(argc==2)

       {

              ret=myftw(argv[1],myfunc1);

             

              ntot=nreg+ndir+nblk+nchr+nfifo+nslink+nsock;

              if(ntot==0)ntot=1;

                printf("totalfiles=%7ld\n",ntot);

              printf("regular files   =%7ld, %5.2f%%\n",nreg,nreg*100.0/ntot);

              printf("directories     =%7ld, %5.2f%%\n",ndir,ndir*100.0/ntot);

              printf("block special   =%7ld, %5.2f%%\n",nblk,nblk*100.0/ntot);

              printf("char special    =%7ld, %5.2f%%\n",nchr,nchr*100.0/ntot);

              printf("FIFOs           =%7ld, %5.2f%%\n",nfifo,nfifo*100.0/ntot);

              printf("symbolic links  =%7ld, %5.2f%%\n",nslink,nslink*100.0/ntot);

              printf("sockets         =%7ld, %5.2f%%\n",nsock,nsock*100.0/ntot);

              printf("filesize<4096   =%7ld, %5.2f %%\n",size,size*100.0/ntot);

       }

       else if(argc>=4)

       {

              if(argc==4&&strcmp(argv[2],"-comp")==0)

              {

                     if((fd=open(argv[3],O_RDONLY))==-1)

                            err_ret("can'topen the file %s\n",argv[4]);

                     lstat(argv[3],&buf);// lstat函数通过文件名filename获取文件信息,并保存在buf所指的结构体stat中

                     dsize=buf.st_size;

                     dbuf=(char*)malloc(sizeof(char)*dsize);

                     read(fd,dbuf,dsize);

                     close(fd);

                     count=0;

                     ret=myftw(argv[1],myfunc2);

                     if(count==0)printf("can't find the file.\n");

              }

              if(strcmp(argv[2],"-name")==0)

              {

                     for(i=4;i<=argc;i++)

                     {

                            count=0;

                            printf("thepaths of this file '%s':\n",argv[i-1]);

                            filename=argv[i-1];

                            ret=myftw(argv[1],myfunc3);

                            if(count==0)printf("Nosuch path.\n");

                     }

              }

       }

       exit(ret);

}

#defineFTW_F 1

#defineFTW_D 2

#defineFTW_DNR 3

#defineFTW_NS 4

staticchar *fullpath;

staticint

myftw(char*pathname,Myfunc *func)

{

       int len;

       fullpath=path_alloc(&len);

       strncpy(fullpath,pathname,len);

       fullpath[len-1]=0;

       return(dopath(func));

}

staticint

dopath(Myfunc*func)

{

       struct stat  statbuf;

       struct dirent *dirp;

       DIR *dp;

       int ret;

       char *ptr;

       if(lstat(fullpath,&statbuf)<0)

              return(func(fullpath,&statbuf,FTW_NS));

       if(S_ISDIR(statbuf.st_mode)==0)  

              return(func(fullpath,&statbuf,FTW_F));

       if((ret=func(fullpath,&statbuf,FTW_D))!=0)

              return(ret);

      

       ptr=fullpath+strlen(fullpath);

       *ptr++='/';

       *ptr=0;

      

       if((dp=opendir(fullpath))==NULL)

              return(func(fullpath,&statbuf,FTW_DNR));

       while((dirp=readdir(dp))!=NULL)

       {

              if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0)

                     continue;

              strcpy(ptr,dirp->d_name);

              if((ret=dopath(func))!=0)

                     break;

       }

       ptr[-1]=0;//等同 *[ptr-1]=0;

       if(closedir(dp)<0)

              err_ret("cant close directory%s",fullpath);

       return(ret);

}

staticint

myfunc1(constchar *pathname,const struct stat *statptr,int type)

{

       switch(type){

       case FTW_F:

              if(statptr->st_size<4096)size++;

              switch(statptr->st_mode&S_IFMT){

              case S_IFREG: nreg++;  break;

              case S_IFBLK: nblk++;  break;

              case S_IFCHR: nchr++;  break;

              case S_IFIFO: nfifo++; break;

              case S_IFLNK: nslink++; break;

              case S_IFSOCK: nsock++; break;

              case S_IFDIR:

                     err_dump("for S_IFDIRfor %s",pathname);

              }

              break;

              case FTW_D:

                     ndir++;

                     break;

              case FTW_DNR: break;

              case FTW_NS: break;

       }

       return(0);

}

staticint

myfunc2(constchar *pathname,const struct stat *statptr,int type)

{

       int fd,len;

       char *buf,*fullpathname;

       buf=(char *)malloc(sizeof(char)*dsize);

       fullpathname=path_alloc(&len);

       if(type==FTW_F)

       {

              if(dsize==statptr->st_size)

              {

                     if((fd=open(pathname,O_RDONLY))==-1)

                            err_ret("cant'topen file\n");

                     read(fd,buf,dsize);

                     if(strcmp(dbuf,buf)==0)

                     {

                            getcwd(fullpathname,len);

                            count++;

                            if(*pathname=='/')printf("%s\n",pathname);

                            elseif(*pathname=='.')

                            {

                                   strcat(fullpathname,pathname+2);

                                   printf("%s\n",fullpathname);

                            }

                            else

                            {

                                   strcat(fullpathname,"/");

                                   strcat(fullpathname,pathname);

                                   printf("%s\n",fullpathname);

                            }

                     }

                     close(fd);

              }

       }

       return(0);

}

staticint

myfunc3(constchar *pathname,const struct stat *statptr,int type)

{

       int len;

       char *fullpathname;

       const char *q;

       fullpathname=path_alloc(&len);

       if(type==FTW_F)

       {

              getcwd(fullpathname,len);

              q=pathname+(strlen(pathname)-1);

              while(*q!='/') q--;

              if(strcmp(filename,++q)==0)

              {

                     count++;

                     if(*pathname=='/')printf("%s\n",pathname);

                     else if(*pathname=='.')

                     {

                            strcat(fullpathname,pathname+2);

                            printf("%s\n",fullpathname);

                     }

                     else

                     {

                            strcat(fullpathname,"/");

                            strcat(fullpathname,pathname);

                            printf("%s\n",fullpathname);

                     }

              }

       }

       return(0);

}

 

 

 

四、实验运行及结果

源程序名:myfind.c

可执行文件:myfind

编译方法:gcc myfind.c error2e.c –o myfind

结束方法:ctrl+c

 

运行过程:

 

1.编译

UNIX程序设计实验三 目录树的遍历

2.实现第一个功能:

UNIX程序设计实验三 目录树的遍历

其中在/home/gu12/gu123104/expmt/3文件目录中总共存在六个文件,其中一个目录文件(.开头的隐藏文件),另有一个小于4096字节的文件(error2e.c).

3.实现第二个功能:判定文件名相同且文件内容一样

当我们对其中/home/gu12/gu123104/expmt/3目录中的apue.h做一下修改,再去实现,则情况如下:

也就找不到内容一样的apue.h文件了,只有本身。

4.实现第三个功能:

1)通过绝对路径实现:

尽管我们刚把apue.h做过了修改,但还是把目录下所有的apue.h文件都输出了,因为他只需要找到相同的名字。

2)通过相对路径实现:

在相对路径下也能实现。

 

①  总结

a.      length=lseek(fd2,0,SEEK_END);

用于确定文件的长度

        b.  原型声明:externchar *strcpy(char *dest,const char *src);

       头文件:string.h

       功能:把从src地址开始且含有NULL结束符的字符串赋值到以dest开始的地址空间

        说明:srcdest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

        返回指向dest的指针。

        c.   语法:struct dirent* readdir(DIR* dir_handle);

 返回值: dirent的结构类型

 函数种类文件存取

 内容说明本函数用来读取目录。返回是dirent结构体指针,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 文件名长 */

unsigned char d_type; /* the type of d_name 文件类型 */

char d_name[NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */

}