遍历目录的主要思想

  由于目录就是一颗树,所以遍历目录就转换为遍历一棵树。谈到树的遍历就再熟悉不过了,有树的前序、层次和后序遍历,我使用的是前序遍历,后序遍历和前序遍历本质上一样,而层次遍历要比前两个麻烦些,我两个都实现了,现在贴出来分享下。

前序遍历

  前序遍历和树的遍历一样,我先显示当前目录的信息,然后遍历目录中的目录项,如果目录项是一个目录则先递归这个子目录,否则如果是目录项是非目录的话就返回。

static void DoTraverDir(MyFunc myFunc)
{
struct stat statBuf;
DIR *pDir;
struct dirent *pDirent;
int pathLen, direntLen; // printf("path: %s\n", fullPath);
//获取当前目录信息,用lstat防止嵌套调用
if (lstat(fullPath, &statBuf) == )
myFunc(fullPath, &statBuf, TD_F);
else
{
myFunc(fullPath, &statBuf, TD_NS); //无法获取信息
return;
}
if (!S_ISDIR(statBuf.st_mode)) //当前路径为文件
return; //处理目录
pathLen = strlen(fullPath);
if (pathLen >= MAX_PATH - ) //目录长度限制,不再处理更深层的目录
return;
if ((pDir = opendir(fullPath)) == NULL)
{
myFunc(fullPath, &statBuf, TD_DNR); //无法读取目录
return;
}
if (fullPath[pathLen - ] != '/')
fullPath[pathLen++] = '/';
//遍历目录中的所有目录项
while ((pDirent = readdir(pDir)) != NULL)
{
//忽略.和..目录项
if (strcmp(pDirent->d_name, ".") == ||
strcmp(pDirent->d_name, "..") == )
continue;
direntLen = strlen(pDirent->d_name);
if (pathLen + direntLen > MAX_PATH) //路径超过了最大长度
return;
strcpy(fullPath + pathLen, pDirent->d_name);
fullPath[pathLen + direntLen] = ;
DoTraverDir(myFunc); //递归处理下一层
}
fullPath[pathLen - ] = ;
if (closedir(pDir) == -)
printf("close dir error : %s\n", fullPath);
}

代码中的fullPath是一个全局变量,用来存放当前遍历文件的路径,路径的最大长度为4096,超过了4096函数自己返回,不进行任何的处理,定义如下:

1 #define MAX_PATH 4096
2 static char fullPath[MAX_PATH + 1];

  还有一个地方值得注意,那就是我上面红色标识的代码,遍历完目录后必须将当前目录关闭掉,否则程序占有的打开目录资源会超过系统的限制,当遍历到了一定的数量后,后面的遍历都会失败,我就是开始没有关闭目录,所以后面出现莫名其妙的错误。

层次遍历

  层次遍历要比前序遍历复杂点,因为是要先处理好了当前目录中的所有目录项后再处理下一层的目录。所有在遍历当前目录的目录项时必须保存下层目录的路径信息,以方便处理下层目录。不过和前面代码的实现也差不多,就是多了一个保存路径的容器罢了,代码如下:

static void DoTraverDir(MyFunc myFunc)
{
struct stat statBuf;
DIR *pDir;
struct dirent *pDirent;
int pathLen, direntLen;
std::vector<std::string> vpDirent;
std::vector<std::string>::iterator vpDirentIterator;
std::string str; // printf("path: %s\n", fullPath);
//获取当前目录信息,用lstat防止嵌套调用
if (lstat(fullPath, &statBuf) == 0)
myFunc(fullPath, &statBuf, TD_F);
else
{
myFunc(fullPath, &statBuf, TD_NS); //无法获取信息
return;
}
//处理目录
pathLen = strlen(fullPath);
if (pathLen >= MAX_PATH - 2) //目录长度限制,不再处理更深层的目录
return;
if ((pDir = opendir(fullPath)) == NULL)
{
myFunc(fullPath, &statBuf, TD_DNR); //无法读取目录
return;
}
if (!S_ISDIR(statBuf.st_mode)) //当前路径为文件
return;
if (fullPath[pathLen - 1] != '/')
fullPath[pathLen++] = '/';
//遍历目录中的所有目录项 while ((pDirent = readdir(pDir)) != NULL)
{
//忽略.和..目录项
if (strcmp(pDirent->d_name, ".") == 0 ||
strcmp(pDirent->d_name, "..") == 0)
continue;
direntLen = strlen(pDirent->d_name);
if (pathLen + direntLen > MAX_PATH) //路径超过了最大长度
return;
strcpy(fullPath + pathLen, pDirent->d_name);
fullPath[pathLen + direntLen] = 0;
if (lstat(fullPath, &statBuf) != 0)
{
myFunc(fullPath, &statBuf, TD_NS); //无法获取信息
continue;
}
if (S_ISDIR(statBuf.st_mode)) //当前路径为目录
vpDirent.push_back(pDirent->d_name);
else
myFunc(fullPath, &statBuf, TD_F);
}
if (closedir(pDir) == -1)
{
fullPath[pathLen - 1] = 0;
printf("close dir error : %s\n", fullPath);
} for (vpDirentIterator = vpDirent.begin(); vpDirentIterator != vpDirent.end(); ++vpDirentIterator)
{
str = *vpDirentIterator;
direntLen = str.length();
strcpy(fullPath + pathLen, str.c_str());
fullPath[pathLen + direntLen] = 0;
DoTraverDir(myFunc);
}
}

  

回调函数

  上面程序中的回调函数MyFunc是用来显示每个文件的信息和对所遍历信息的统计,下面是该函数的具体实现:

void ShowInfo(const char *pathName, const struct stat *statBuf, int type)
{
switch (type)
{
case TD_F:
if (S_ISREG(statBuf->st_mode)) //普通文件
nReg++;
else if (S_ISDIR(statBuf->st_mode)) //目录
nDir++;
else if (S_ISCHR(statBuf->st_mode)) //字符文件
nChr++;
else if (S_ISBLK(statBuf->st_mode)) //块文件
nBlk++;
else if (S_ISFIFO(statBuf->st_mode)) //管道文件
nFifo++;
else if (S_ISLNK(statBuf->st_mode)) //链接文件
nLink++;
else if (S_ISSOCK(statBuf->st_mode)) //套接字文件
nSock++;
else //未知文件类型
{
nKno++;
printf("unknow file type : %s\n", pathName);
}
break;
case TD_NS:
nNs++;
printf("can't state file : %s\n", pathName);
break;
case TD_DNR:
nDnr++;
printf("can't open dir : %s\n", pathName);
break;
default:
printf("unkonw type\n");
}
}

  

linux下遍历目录(转-在于思考)的更多相关文章

  1. Linux下遍历目录及文件,更改权限

    Linux下遍历目录及文件,更改权限 引言: 我在Linux下搭建android时,将eclipse及sdk复制到/usr/下时,总会出现无法读,无法写写样的问题. 解决方案: 有两个方案: 一.将复 ...

  2. linux下遍历目录

    遍历目录的主要思想 由于目录就是一颗树,所以遍历目录就转换为遍历一棵树.谈到树的遍历就再熟悉不过了,有树的前序.层次和后序遍历,我使用的是前序遍历,后序遍历和前序遍历本质上一样,而层次遍历要比前两个麻 ...

  3. 在Linux下和Windows下遍历目录的方法及如何达成一致性操作

    最近因为测试目的需要遍历一个目录下面的所有文件进行操作,主要是读每个文件的内容,只要知道文件名就OK了.在Java中直接用File类就可以搞定,因为Java中使用了组合模式,使得客户端对单个文件和文件 ...

  4. linux下mnt目录作用

    linux下mnt目录作用 一.mount 英文解释 登上; 爬上; 攀登; 骑上; 乘上; 跨上 可直接理解为“挂载” 挂接光驱.USB设备的目录,加载后,会在mnt里多出相应设备的目录.mnt是m ...

  5. 【收集整理】Linux下的目录讲解

    Linux下的目录介绍:在Linux系统中,一切东西都是存放在一个唯一的“虚拟文件系统”中的,这个“虚拟文件系统”是树状的结构以一个根目录开始.以文件来表示所有逻辑实体和非逻辑实体,逻辑实体指文件和目 ...

  6. linux下各目录的作用

    这么久了,一直觉得对于linux的运作情况还是懵懵懂懂的样子,刚才专门又看了一下 linux 下各目录的作用,记下来,以备以后再忘了. 下面内容来自:http://www.linuxidc.com/L ...

  7. linux下为目录和文件设置权限

    摘:linux下为目录和文件设置权限 分类: Linux2012-05-09 03:18 7456人阅读 评论(1) 收藏 举报 linuxwordpressweb数据库serverfile linu ...

  8. Linux下查看目录文件数和文件大小

    一.查看当前目录下文件个数 在linux下查看目录下有多少文件可以用:ls -l  命令查看,ls -lR 递归查看所有目录, 如果文件很多,则用wc命令 和 grep 命令进行过滤. wc命令显示输 ...

  9. 【ARM-Linux开发】Linux下更改目录下所有文件的所有者及其权限

    [ARM-Linux开发]Linux下更改目录下所有文件的所有者及其权限 chown 更换所有者: chmod 改变权限: 想一次修改某个目录下所有文件的权限,包括子目录中的文件权限也要修改,要使用参 ...

随机推荐

  1. subline快捷键

    折叠所有代码:  按ctrl+k,再按ctrl+1 展开所有代码: 按ctrl+k,再按ctrl+j 折叠此处代码:  ctrl+shift+[ 展开此处代码: ctrl+shift+]

  2. android中正确导入第三方jar包

    android中正确导入第三方jar包 andriod中如果引入jar包的方式不对就会出现一些奇怪的错误. 工作的时候恰好有一个jar包需要调用,结果用了很长时间才解决出现的bug. 刚开始是这样引用 ...

  3. SharePoint 2013 企业搜索架构示例

    博客地址:http://blog.csdn.net/FoxDave 本文参考自微软官方的Chart,我们来看一下企业中对于不同规模SharePoint搜索的场的架构是什么样的. 对于搜索场的规模, ...

  4. php的查询数据

    php中 连接数据库,通过表格形式输出,查询数据.全选时,下面的分选项都选中;子选项取消一个时,全选按钮也取消选中. <!DOCTYPE html PUBLIC "-//W3C//DT ...

  5. ACM2013.9.7

    acm还是要好好做的,还有好多的东西要学呢!不能不认真对待了,该玩够了!

  6. 黑马程序员——【Java基础】——Java概述

    ---------- android培训.java培训.期待与您交流! ---------- 一.Java语言概述及三大技术架构 1.Java语言概述 Java是SUN公司于1995年推出的一种面向I ...

  7. 封装数据库mysql, mysqli

    <?php header("content-type:text/html;charset=utf-8"); class db{    //私有的静态属性    private ...

  8. BZOJ 2442 修剪草坪

    NOIP的时候一定要看清楚数据范围. #include<iostream> #include<cstdio> #include<cstring> #include& ...

  9. html网页标题

    HTML代码 <html> <head> <!--<title>定义网页标题,显示在浏览器的标题--> <title>网页标题</ti ...

  10. ACE - 代码层次及Socket封装

    原文出自http://www.cnblogs.com/binchen-china,禁止转载. ACE源码约10万行,是c++中非常大的一个网络编程代码库,包含了网络编程的边边角角.在实际使用时,并不是 ...