您的位置:首页 > 编程语言 > C语言/C++

基于ACE实现C++目录遍历

2006-03-15 00:00 986 查看
目录遍历,在软件编程中属于常见的需求;如:病毒扫描、源代码编辑、文件比较。在windows环境,使用FindFirstFileEx、FindNextFile(详细情况可以参考MSDN)等文件访问函数,能够实现目录遍历;在posix环境,可以使用open_dir。跨平台不是这里讨论的重点。
ACE提供的opendir_emulation、readdir_emulation函数族与Windows的FindFirstFileEx、FindNextFile功能是一致的;其本意也是提供一种类似接口的跨平台封装。但是,直到版本4.361都还是没有加入其它平台的处理;现在只能认为ACE把一些内存管理包装到自己的函数族中了。
以下的讨论也基于如上的函数实现。

目录的组织可以分成3种情况:
1) 下面也是目录;
2) 下面是文件;
3) ‘.’和‘..’
其中‘.’和‘..’比较特殊,需要过滤。基于上述分析,函数递归调用的算法比较简单。为代码如下:
打开目录;
如果是文件,调用文件处理函数;
如果是目录:
如果目录名是‘.’或者‘..’,继续;
对目录下所有内容:
调用本函数;
读取目录;
清除处理
本文讨论的是:如何基于OO的实现。明显的,如上的递归算法可以封装到一个类中,这是不变的地方;变化的是对文件的处理,比如:打印,扫描等。检查算法,文件处理,可以用虚函数,实现hook处理,可以通过重载此函数实现功能拓展。另外,容易考虑到的内容是,文件过滤,如对*.exe或者*.cpp进行某种操作。
有了如上的分析,容易得到如下的类定义:
class DirVisitor
{
public:
void get_one_dir(const string& parent, const string& dir_name)
{
struct ACE_DIR* base_dir = ACE_OS::opendir_emulation(parent.c_str());
if(!base_dir)
{
#if 0
cout << parent.c_str() << " is a file" << endl;
#endif
if(!bypass(parent.c_str()))
{
handle_one_file(parent, dir_name);
}
}
else
{
//remove . and .. directory
struct ACE_DIRENT * dir = ACE_OS::readdir_emulation(base_dir);
//对posix可以换成dir == “.” || dir == “..”这样可以处理隐含文件。
while(dir && dir->d_name[0] == '.')
{
//对posix,隐含文件被忽略。
dir = ACE_OS::readdir_emulation(base_dir);
}
//recursive call
while(dir)
{
get_one_dir(parent + "//" + dir->d_name, string(dir->d_name));
dir = ACE_OS::readdir_emulation(base_dir);
}
ACE_OS::closedir_emulation(base_dir);
}
}
protected:
virtual int handle_one_file(const string& path_name, const string& dir_name)
{
cout << path_name.c_str() << endl;
return 0;
}
virtual bool comparer(const string& name, const string& key)
{
if(string::npos != name.find(key))
{
return true;
}
return false;
}
virtual bool bypass(const string& name)
{
//always not by pass
return false;
}
};
类的对外借口只有一个open_one_dir,其他的都被封装起来;可以拓展的是3个保护函数:
1) handle_one_file:提供一种默认处理,打印到标准输出;
2) comparer:文件名比较方法,默认是字符串包含与否的比较;可以拓展为模糊比较;
3) bypass:忽略文件的条件;这里默认不忽略。
这样客户端代码就简单了:
int main(int argc, char** argv)
{
//从命令行参数中传入起始目录
if(argc == 1)
{
cout << "using:" << argv[0] << " [source directory]." << endl;
exit(0);

}
DirVisitor visitor;
visitor.get_one_dir(string(argv[1]), string(""));
}
这样的代码能够显示一个目下的所有目录和文件。如ace/doc目录的扫描结果:

E:/tools/ACE_wrappers/docs/ACE-bug-process.html
E:/tools/ACE_wrappers/docs/ACE-categories.html
E:/tools/ACE_wrappers/docs/ACE-configuration.txt
E:/tools/ACE_wrappers/docs/ACE-development-process.html
E:/tools/ACE_wrappers/docs/ACE-FMM.html
E:/tools/ACE_wrappers/docs/ACE-guidelines.html
E:/tools/ACE_wrappers/docs/ACE-lessons.html
E:/tools/ACE_wrappers/docs/ACE-porting.html
E:/tools/ACE_wrappers/docs/ACE-SSL.html
E:/tools/ACE_wrappers/docs/ACE-subsets.html
E:/tools/ACE_wrappers/docs/ace_guidelines.vsmacros
E:/tools/ACE_wrappers/docs/CE-status.txt
E:/tools/ACE_wrappers/docs/CVS.html
E:/tools/ACE_wrappers/docs/exceptions.html
E:/tools/ACE_wrappers/docs/index.html
E:/tools/ACE_wrappers/docs/msvc_notes.txt
E:/tools/ACE_wrappers/docs/README.tutorials
E:/tools/ACE_wrappers/docs/run_test.txt
E:/tools/ACE_wrappers/docs/usage-bugzilla.html
E:/tools/ACE_wrappers/docs/wchar.txt
Press any key to continue

要进行过滤,只要重载bypass,这里提供一种对c++文件显示的范例:
bool CPlusVisitor::bypass(const string& name)
{
if(comparer(name, string(".h")))
{
return false;
}
if(comparer(name, string(".c")))
{
return false;
}
if(comparer(name, string(".C")))
{
return false;
}
if(comparer(name, string(".cpp")))
{
return false;
}
if(comparer(name, string(".i")))
{
return false;
}
if(comparer(name, string(".inl")))
{
return false;
}

return true;
}
关于handle_one_file方法:参数1,path_name提供了带路径的文件名;参数2,key提供不带路径的文件名,方便处理。
小结:这里提供的基于ACE的目录遍历,由于其OO的封装,方便实用;使用ACE的目的就是利用其跨平台的包装。为了目录遍历的跨平台性,可以自己封装posix的opendir_emulation、readdir_emulation函数族,也可以等待ACE提供^---^。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: