Directory Searching
Site Map Feedback

Download:

Up DTree Local Picker Recycle ResFile Temp

These classes allow you to iterate Files and Directories (optionally having a specified extension) in a specified Directory. If you're just after a directories file and folder count and sizes, look at CFolderSizer in LocalPath.h

FileDetails.h holds the usual information for a file and can be set directly from a WIN32_FIND_DATA structure. CFileDetails has a Compare method and serialization operators and is used by DTree.

There are two classes CDtree and CQDTree. CDTree sorts the Directory Tree so that Directories come before Files and all items are in name order alphabetically (case insensitive). CQDTree is a Quick (unsorted) version. Windows NT, XP and Vista give sorted output (case sensitive) using CQDTree, but Windows 98 returns the Files in whatever order they happen to be on the Disk.

CDTree which uses an AVL Binary Tree for the sorting which should be the fastest method. In the search for a simpler class, the sort speed was tested using a powerful workstation with RAM disk to ignore disk access times. The sorting took a third of the time of the rest of the process (So if the directory scan is going to take 3 minutes using the unsorted CQDTree class, it will take four minutes using the sorted CDTree class).

To deal with each File or Directory in a given Directory:
#include "DTree.h"
void main() {
  CDTree DTree;
  if(DTree.GetList("V:\\Programming\\C++\\TestApps\\DirectoryTester","*.cpp")) {
    CString S;
    while(DTree.GetNext(S)) {
      bool Directory=DTree.IsDirectory();
      // Deal with it here...
} } }
The order of the search is as you would see the results in a fully expanded tree representation, top to bottom.
There is an IsLast() function to tell you if this is the last File Object in the current directory.

You can 'recursively' deal with each File or Directory from a given Path. The algorithm is efficient, doesn't use recursion and provides extra information (like if the File you're currently dealing with is the last File Object in this Directory. To do this you call the CDTree::FromPath method or use the appropriate constructor (as shown below).

This Method will call three event handlers that you design in a Behaviour Class derived from CDTreeBehaviour.
OnDIR is called when a Directory is found.
At this point GetCurrentDirectoryName(), GetPath() and GetDepth() are of the Directory where you are, and GetName() is of the Directory you're going into.
OnFile is called when a File is found.
At this point GetName() is of the File, and GetPath(), GetCurrentDirectoryName() and GetDepth() are of the Directory that the file is in.
OnUp is called when the search goes up a level.
At this point GetPath() is where you are, and GetCurrentDirectoryName(), GetName() and GetDepth() are of the Directory you've just finished scanning.
You need to create this small class to describe the behaviour that you want to be performed on each event; here CDTreeViewer has been created as an example.
The example produces a full directory tree listing:
+-dir1
| +-dir11
| | \-fName11
| \-dir12
|   +-fName.txt
|   \-fName12
\-dir2
  +-dir21
  | +-fName.txt
  | \-fName21
  +-dir22
  | +-Copy of fName22
  | +-fName.txt
  | \-fName22
  +-fName.txt
  \-fName2
#include "DTree.h"
#include "ioStream.h"  // For cout
#include <direct.h>    // For mkdir
#include <conio.h>     // For getch

class CDTreeViewer: public CDTreeBehaviour {
  bool Done[MAX_PATH];
public:
  CDTreeViewer(const CString& Path) {
    CString S;
    DWORD Length=GetFullPathName(Path,0,0,0); // Make relative paths absolute:
    GetFullPathName(Path, Length, S.GetBufferSetLength(Length), 0);
    S.ReleaseBuffer();
    cout << (const char*)(S) << endl;

    memset(Done, false, MAX_PATH);
    CDTree(Path, *this);
  }
private:
  void OnUp  (CDTreeBase& DTreeBase) {Done[DTreeBase.GetDepth()]=false;}
  void OnDIR (CDTreeBase& DTreeBase) {OnFile(DTreeBase);}
  void OnFile(CDTreeBase& DTreeBase) {
    CString S(DTreeBase.GetPath()+'\\'+DTreeBase.GetName());
    for(int i=0; i<DTreeBase.GetDepth(); ++i) cout << (Done[i] ? "  " : "| ");
    cout << (DTreeBase.IsLast() ? '\\' : '+') << '-' << (const char*)(DTreeBase.GetName()) << endl;
    if(DTreeBase.IsLast()) Done[DTreeBase.GetDepth()]=true;
  }
};

void main() {
  mkdir("Test"                                                );
  mkdir("Test\\dir1"                                          );
  mkdir("Test\\dir1\\dir11"                                   );
  CFile("Test\\dir1\\fName11"               ,CFile::modeCreate);
  mkdir("Test\\dir1\\dir12"                                   );
  CFile("Test\\dir1\\dir12\\fName.txt"      ,CFile::modeCreate);
  CFile("Test\\dir1\\dir12\\fName12"        ,CFile::modeCreate);
  mkdir("Test\\dir2"                                          );
  mkdir("Test\\dir2\\dir21"                                   );
  CFile("Test\\dir2\\dir21\\fName.txt"      ,CFile::modeCreate);
  CFile("Test\\dir2\\dir21\\fName21"        ,CFile::modeCreate);
  mkdir("Test\\dir2\\dir22"                                   );
  CFile("Test\\dir2\\dir22\\Copy of fName22",CFile::modeCreate);
  CFile("Test\\dir2\\dir22\\fName.txt"      ,CFile::modeCreate);
  CFile("Test\\dir2\\dir22\\fName22"        ,CFile::modeCreate);
  CFile("Test\\dir2\\fName.txt"             ,CFile::modeCreate);
  CFile("Test\\dir2\\fName22"               ,CFile::modeCreate);

  CDTreeViewer(".");
  getch();
}
The following code saves a directory tree to a text file in a compact manner:
The top line is the start path.
Lines starting with a dot '.' specify a directory name.
Lines starting with anything other than a dot are files within the last specified directory.
Lines containing two dots mean "go up a directory".
class CDTreeSaver: public CDTreeBehaviour {
public:
  CDTreeCat(CString Path) : pFile(0), pAr(0) {
    pFile=new CFile;
    if(!pFile->Open("C:\\S.TXT",CFile::modeCreate|CFile::modeWrite)) return;
    pAr=new CArchive(pFile,CArchive::store);
    pAr->WriteString(Path+"\r\n");
    CDTree(Path, *this);
  }
  ~CDTreeCat() {delete pAr; delete pFile;}
private:
  CFile* pFile;
  CArchive* pAr;
  void OnFile(CDTreeBase& DTreeBase) {pAr->WriteString(    DTreeBase.GetName()+"\r\n");}
  void OnDIR (CDTreeBase& DTreeBase) {pAr->WriteString('.'+DTreeBase.GetName()+"\r\n");}
  void OnUp  (CDTreeBase& DTreeBase) {pAr->WriteString("..\r\n");}
};
The following projects in the Freeware section of this site demonstrate the use of DTree.h:
[CopyTree] Directory Tree Copier
[Name] Picture File Automatic Namer
[Zeroed] Zeroed File Finder

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


 (1733) Last modified: Fri, 05 Jun 2009 17:05:12 +0100