visitor.cpp
上传用户:dfhlxjd
上传日期:2007-01-07
资源大小:12k
文件大小:4k
源码类别:

Shell编程

开发平台:

Visual C++

  1. //----------------------------------------
  2. // (c) Reliable Software 1997
  3. //----------------------------------------
  4. #include "visitor.h"
  5. #include "main.h"
  6. class FileIter
  7. {
  8. public:
  9.     FileIter(char const * pattern);
  10.     ~FileIter()
  11.     {
  12.         FindClose(_handle);
  13.     }
  14.     bool AtEnd() const {return _atEnd;}
  15.     void Advance()
  16.     {
  17.         _atEnd = !FindNextFile (_handle, &_data);
  18.     }
  19.     char const * GetFileName() const {return _data.cFileName;}
  20. protected:
  21.     bool            _atEnd;
  22.     HANDLE          _handle;
  23.     WIN32_FIND_DATA _data;
  24. };
  25. FileIter::FileIter (char const * pattern)
  26.     :_atEnd (false)
  27. {
  28.     _handle = FindFirstFile (pattern, &_data);
  29.     if (_handle == INVALID_HANDLE_VALUE)
  30.     {
  31.         int err = GetLastError ();
  32.         if (err == ERROR_FILE_NOT_FOUND)
  33.             _atEnd = true;
  34.         else
  35.         {
  36.             throw WinException ("Internal error: FindFirstFile failed");
  37.         }
  38.     }
  39.     // skip links to the current and parent directories
  40.     while (!_atEnd && _data.cFileName [0] == '.')
  41.         _atEnd = !FindNextFile (_handle, &_data);
  42. }
  43. // Usage:
  44. // Declare a Sizer visitor
  45. // Declare a Traversal using full path
  46. // Retrieve total size from the visitor
  47. Traversal::Traversal (Path & path, Visitor & visitor)
  48.     : _visitor (visitor)
  49. {
  50.     TraverseTree (path);
  51. }
  52. Traversal::Traversal (char const * directoryName, Visitor & visitor)
  53.     : _visitor (visitor)
  54. {
  55.     Path path(directoryName);
  56.     TraverseTree (path);
  57. }
  58. void Traversal::TraverseTree (Path & curPath)
  59. {
  60.     // list all *.* files and directories
  61.     for (FileIter iter (curPath.WildcardPath ()); !iter.AtEnd (); iter.Advance ())
  62.     {
  63.         char const * name = iter.GetFileName ();
  64.         if (_visitor.Visit (name))
  65.         {
  66.             // Visitor found folder
  67.             curPath.DirDown (name);
  68.             TraverseTree (curPath);
  69.             curPath.DirUp ();
  70.         }
  71.     }
  72. }
  73. class File
  74. {
  75. public:
  76.     ~File () { Close (); }
  77.     bool    FileOk () { return _hFile != INVALID_HANDLE_VALUE; }
  78.     ULONG   GetSize () const { return _size; }
  79.     void    InitSize ();
  80.     static bool IsFolder (char const * path);
  81. protected:
  82.     File () : _hFile (INVALID_HANDLE_VALUE), _size (0) {}
  83.     void    OpenReadOnly (char const * path);
  84.     void    Close ();
  85.     HANDLE  _hFile;
  86.     ULONG   _size;
  87. };
  88. bool File::IsFolder (char const * path)
  89. {
  90. SetLastError(NO_ERROR);
  91. bool rval = false;
  92. try
  93. {
  94.     DWORD attr = GetFileAttributes (path);
  95. rval = (attr != 0xffffffff) && (attr & FILE_ATTRIBUTE_DIRECTORY);
  96. }
  97. catch (...)
  98. {
  99. rval = false;
  100. }
  101.     return rval;
  102. }
  103. void File::OpenReadOnly (char const *path)
  104. {
  105.     _hFile = CreateFile (
  106.                             path,
  107.                             GENERIC_READ,
  108.                             FILE_SHARE_READ,
  109.                             0,
  110.                             OPEN_EXISTING,
  111.                             FILE_ATTRIBUTE_NORMAL,
  112.                             0);
  113.     if (!FileOk ())
  114.     {
  115.         throw "Internal error: Read only open file failed.";
  116.     }
  117. }
  118. void File::Close ()
  119. {
  120.     if (FileOk())
  121.     {
  122.         CloseHandle (_hFile);
  123.         _hFile = INVALID_HANDLE_VALUE;
  124.     }
  125. }
  126. void File::InitSize ()
  127. {
  128.     ULONG sizeHigh;
  129.     _size = ::GetFileSize (_hFile, &sizeHigh);
  130.     if (sizeHigh != 0)
  131.         throw "Internal error: File too big (> 4GB)";
  132.     if (0xFFFFFFFF== _size && NO_ERROR != GetLastError ())
  133.     {
  134.         Close ();
  135.         throw "Internal error: Get file size failed.";
  136.     }
  137. }
  138. class FileInfo: public File
  139. {
  140. public:
  141.     FileInfo (char const *path)
  142.     {
  143.         OpenReadOnly (path);
  144.         InitSize ();
  145.     }
  146. };    
  147. bool Sizer::Visit (char const * name)
  148. {
  149.     bool recurse = false;
  150.     // IsFolder sets the thread error
  151.     SetLastError(NO_ERROR);
  152.     if (File::IsFolder (name))
  153.     {
  154.         recurse = true;
  155.     }
  156.     else
  157.     {
  158.         if (GetLastError() == NO_ERROR)
  159.         {
  160. try
  161. {
  162.             FileInfo info (name);
  163.             _totalSize += info.GetSize ();
  164. }
  165. catch (...)
  166. {
  167. // file info couldn't be fetched - not a fatal error,
  168. // just skip counting...
  169. }
  170.         }
  171.     }
  172.     return recurse;
  173. }