Directory traverses, which belongs to common requirements in software programming; such as viral scan, source code editing, file comparison. In the Windows environment, file access functions such as FINDFIRSTFILEEX, FINDNEXTFILEX, FINDNEXTFILE (Details) can be used to achieve directory traverses; Open_DIR can be used in the POSIX environment. Cross-platform is not the focus of discussion here.
The OpenDir_emulation provided by the ACE is consistent with Windows's FindFirstFileEx, and the FindNextFile feature is consistent; it is also a cross-platform package that provides a similar interface. However, until version 4.361 is still not added to other platforms; now I can only think that ACE packs some memory management into their own function family.
The following discussion is also implemented based on the above functions.
The organization of the catalog can be divided into three cases:
1) The following is also a directory;
2) The following is the file;
3) '.' And '..'
Where '.' And '..' is special, need to filter. Based on the above analysis, the algorithm of the function recursive call is relatively simple. For the code as follows:
open Directory;
If it is a file, call the file processing function;
If it is a directory:
If the directory name is '.' Or '..', continue;
All contents under the directory:
Call this function;
Read the catalog;
Clearance
This article discusses: how to achieve an OO implementation. Obviously, if the recursive algorithm, the recursive algorithm can be encapsulated into a class, this is the same place; the change is the processing of documents, such as printing, scanning, etc. Check the algorithm, file processing, you can use the virtual function to implement the HOOK processing, you can achieve functional expansion by overloading this function. Additionally, the content that is easy to consider is, file filtering, such as addressing * .exe or * .cpp.
With the above analysis, it is easy to get the following definition:
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);
// The POSIX can be replaced with DIR == "." || DIR == ".." This can process an implicit file.
While (DIR && Dir-> D_Name [0] == '.')
{
// For POSIX, the implied file is ignored.
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)
{
IF (string :: npos! = name.find (key))
{
Return True;
}
Return False;
}
Virtual Bool Bypass (Const String & Name)
{
// always not by pass
Return False;
}
}
The external except of the class has only one Open_ONE_DIR, and the other is packaged; can expand 3 protection functions:
1) Handle_one_file: Provides a default processing, printing to a standard output;
2) Comparer: File name comparison method, the default is the comparison of the string containing or not; can expand as ambiguated comparison;
3) BYPASS: Ignore the conditions of the file; not ignored by default.
This way the client code is simple:
INT main (int Argc, char ** argv)
{
// Incontinence from the command line parameters
IF (argc == 1)
{
COUT << "Using:" << argv [0] << [source directory]. "<< endl;
exit (0);
}
Dirvisitor Visitor;
Visitor.get_one_dir (String (Argv [1]), String (""));
}
Such code can display all of all directories and files. Such as scanning results of the ACE / DOC directory:
E: /Tools/Ace_wrappers/docs/ace-bug-process.htmle: /tools/Ace_wrappers/docs/ace-categories.htmle: /Tools/Ace_wrappers/docs/ace-configuration.txte: / Tools / ACE_WrapPERS / DOCS / Ace-development-process.htmle: /tools/ace_wrappers/docs/ace-fmm.htmle: /Tools/Ace_wrappers/docs/ace-guidelines.htmle: /Tools/Ace_wrappers/docs/ace-lesss.htmle: / Tools / ACE_wrappers / docs / ACE-porting.htmlE: /tools/ACE_wrappers/docs/ACE-SSL.htmlE: /tools/ACE_wrappers/docs/ACE-subsets.htmlE: /tools/ACE_wrappers/docs/ace_guidelines.vsmacrosE: / tools / ACE_wrappers / docs / CE-status.txtE: /tools/ACE_wrappers/docs/CVS.htmlE: /tools/ACE_wrappers/docs/exceptions.htmlE: /tools/ACE_wrappers/docs/index.htmlE: / tools / ACE_wrappers / docs / msvc_notes.txtE: /tools/ACE_wrappers/docs/README.tutorialsE: /tools/ACE_wrappers/docs/run_test.txtE: /tools/ACE_wrappers/docs/usage-bugzilla.htmlE: /tools/ACE_wrappers/docs/wchar.txtPress any Key to Continue To filter, as long as you override BYPASS, you provide an example of displaying C files: BOOL CPLUSVisitor :: Bypass (const string & name)
{
IF (Comparer (Name, String (". h")))))))
{
Return False;
}
IF (Comparer (", String (". C "))))))))))))))
{
Return False;
}
IF (Comparer (", String (". C "))))))))))))))
{
Return False;
}
IF (Comparer (Name, String (". CPP"))))))))))
{
Return False;
}
IF (Comparer (Name, String (". I")))))))))))
{
Return False;
}
IF (Comparer (", inl")))))))))))
{
Return False;
}
Return True;
}
About Handle_One_File method: Parameters 1, Path_name provides file name with path; parameter 2, key provides file name without paths, easy to handle. Summary: The ACE-based catalog is traversed, and it is convenient and practical due to its OO package; the purpose of using ACE is to utilize its cross-platform packaging. In order to spread the cross-platform sex of the catalog, you can package the POSIX OpenDir_emulation, the READDIR_EMULATION function, or wait for ACE to provide ^ - ^.