linux下遍历目录树方法总结,linux下遍历目录树方法总结(下)

2、使用ftw调用遍历目录

2.1ftw函数族

使用readdir函数等实现递归遍历目录树的方法比较原始,glibc2.1收录了ftw等函数,可以方便实现目录树的遍历。

#include 

intftw(constchar*dirpath,

int(*fn) (constchar*fpath,conststructstat *sb,inttypeflag),

intnopenfd);

#define _XOPEN_SOURCE 500

#include 

intnftw(constchar*dirpath,

int(*fn) (constchar*fpath,conststructstat *sb,inttypeflag,structFTW *ftwbuf),

intnopenfd,intflags);

具体的英文解释可以参考文章《 ftw, nftw - file tree walk 》。

ftw()

函数说明:ftw() 会从参数dirpath指定的目录开始,往下一层层地递归式遍历子目录。每一个文件或者目录会调用参数*fn定义的函数来处理。ftw()会传三个参数给fn(), 第一个参数*fpath指向当时所在的目录路径,第二个参数是*sb, 为stat结构指针,第三个参数为flag,有下面几种可能值

FTW_F        一般文件

FTW_D       目录

FTW_DNR    不可读取的目录,此目录以下将不被遍历

FTW_SL       符号连接

FTW_NS       无法取得stat结构数据,有可能是权限问题

最后一个参数depth代表ftw()在进行遍历目录时同时打开的文件数。ftw()在遍历时每一层目录至少需要一个文件描述词,如果遍历时用完了depth所给予的限制数目,整个遍历将因不断地关文件和开文件操作而显得缓慢。(实际做测试的时候未发现...)

如果要结束ftw()的遍历,fn()只需返回一非零值即可,此值同时也会是ftw()的返回值。否则ftw()会试着走完所有的目录,然后返回0

返 回  值:遍历中断则返回fn()函数的返回值,全部遍历则返回0,若有错误发生则返回-1

附加说明:由于ftw()会动态配置内存使用,请使用正常方式(fn函数返回非零值)来中断遍历,不要在fn函数中使用longjmp()

nftw()

函数说明:nftw()与ftw()很像,都是从参数dirpath指定的目录开始, 往下一层层地递归遍历子目录。 每一个文件或者目录会调用参数*fn定义的函数来处理。nftw()会传四个参数给fn(). 第一个参数*fpath指向当时所在的目录路径,第二个参数是*sb, 为stat结构指针(结构定义请参考stat()),第三个参数为typeflag,有底下几种可能值:

FTW_F                         一般文件

FTW_D                         目录

FTW_DNR                      不可读取的目录。此目录以下将不被遍历

FTW_SL                         符号连接

FTW_NS                        无法取得stat结构数据,在可能是权限问题

FTW_DP                        目录,而且子目录都已被遍历过了

FTW_SLN                       符号连接,但连接不存在的文件

fn()的第四个参数是FTW结构,定义如下:

struct  FTW

{

int  base;

int  level; //level代表遍历时的深度

}

nftw()第三个参数depth代表nftw()在进行遍历目录时可同时打开的文件数。

ftw()在遍历时每一层目录至少需要一个文件描述词,如果遍历时用完了depth所给予的限制数目,整个遍历将因不断地关文件和开文件操作而显得的缓慢

nftw()最后一个参数flags用来指定遍历时的动作,可指定下列的操作或用OR组合

FTW_CHDIR                 在读目录之前先用chdir()移到此目录

FTW_DEPTH                执行深度优先搜索。在遍历此目录前先将所有子目录遍历完

FTW_MOUNT               遍历时不要跨越到其他文件系统

FTW_PHYS                  不要遍历符号连接的目录。预设会遍历符号连接目录

如果要结束nftw()的遍历,fn()只需返回一非0值即可,此值同时也会是nftw()的返回值。否则nftw()会试着遍历完所有目录,然后返回0.

返 回 值 :遍历中断则返回fn()函数的返回值, 全部遍历完则返回0,若有错误发生则返回-1

区别:ftw 对于每一个文件他都会调用stat函数,这就造成程序会跟随符号链接。这就可能导致在某些情况下重复某些目录或者循环统计某些目录文件(这是因为符号链接的原因,详细参见UNIX环境高级编程)。

nftw将调用lstat函数所以不存在跟随符号链接的问题。

有一个没搞清楚的问题是我使用FTW_DEPTH 来遍历整个目录树的时候,遍历到proc目录下存在异常返回,可能还需要指定FTW_PHYS使其不遍历符号链接目录,这个有空查一下。

2、遍历的例子

自己写的一个测试的小例子。遍历指定目录,输出文件元数据和遍历深度等信息。

#define _XOPEN_SOURCE 500

#include

#include

#include

#include

#include

#define FILEOPEN 1024

intgb_filecount;

intgetMetadata(constchar*dirpath,conststructstat *sb,inttypeflag,structFTW *ftwbuf);

intmain(intargc,char** argv){

intret = 0;

structstat pathbuf;

if(argc > 2){

printf("-nfwt_t:invalid arguments \n ");

return-1;

}

if(stat(argv[1],&pathbuf)){

printf("-nfwt_t:invalid dirpath:%s\n",argv[1]);

return-1;

}else{

if(0 == S_ISDIR(pathbuf.st_mode)){

printf("-nfwt_t:\"%s\" is not dirpath\n",argv[1]);

return-1;

}

}

gb_filecount=0;

ret = nftw(argv[1],getMetadata,FILEOPEN,FTW_PHYS);

if(ret<0){

printf("-nftw:[wrong:%d]ntfw search %d files\n",ret,gb_filecount);

return-1;

}else{

printf("-nftw:[done:%d]trasvers in %s search %d files\n",ret,argv[1],gb_filecount);

return0;

}

}

int

getMetadata(constchar*dirpath,conststructstat *sb,inttypeflag,structFTW *ftwbuf){

printf("num:%d path:%s ",++gb_filecount,dirpath);

printf("st_dev:%d ",(*sb).st_dev);

printf("st_ino:%d ",(*sb).st_ino);

printf("st_mode:%d S_ISDIR:%d ",(*sb).st_mode,S_ISDIR((*sb).st_mode));

printf("st_nlink:%d ",(*sb).st_nlink);

printf("st_uid:%d ",(*sb).st_uid);

printf("st_gid:%d ",(*sb).st_gid);

printf("st_rdev:%d ",(*sb).st_rdev);

printf("st_size:%d ",(*sb).st_size);

printf("st_blksize:%lu ",(*sb).st_blksize);

printf("st_blocks:%lu ",(*sb).st_blocks);

printf("st_atime:%ld ",(*sb).st_atime);

printf("st_mtime:%ld ",(*sb).st_mtime);

printf("st_ctime:%ld ",(*sb).st_ctime);

printf("typeflag:%d ",typeflag);

printf("FTW_base:%d FTW_level:%d /n",(*ftwbuf).base,(*ftwbuf).level);

return0;

}

目的: 掌握与文件和目录有关的系统调用和库函数。 要求: 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携带的函数指针参数决定。这样程序的结构清晰,可扩充性好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值