65.9K
CodeProject 正在变化。 阅读更多。
Home

Win32 文件名迭代(STL 方式)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (18投票s)

2004年11月21日

1分钟阅读

viewsIcon

142344

downloadIcon

669

这个简单的类展示了如何使用 STL 迭代器接口来迭代文件名。

引言

我曾经多次处理文件名,通常使用 Win32 API,例如 ::FindFirstFile。但这样做非常繁琐。最终,我意识到可以使用 STL 的强大特性——迭代器,来处理文件名迭代。因此,我创建了一个简单的 STL 迭代器类用于文件名迭代。

用法

win32_file_iterator itBegin("c:\\*.*"), itEnd;
std::copy(itBegin, itEnd, ostream_iterator<std::string>(cout, "\n"));

上面的代码展示了使用该类的最简单方法。实际上,我认为你可以使用几乎所有的 STL 算法。

win32_file_iterator itBegin("c:\\*.*"), itEnd;
std::vector<std::string> vec(itBegin, itEnd);

你也可以使用接受起始迭代器和结束迭代器的构造函数来填充 STL 容器。

实际上,win32_file_iterator 类的构造函数接受三个参数。第一个是用于调用 ::FindFirstFile 函数的过滤字符串。第二个是标志,用于指定反引用路径是否为完整路径。例如,如果为 true,则返回的路径字符串为 c:\test\aa.txt,否则仅为 aa.txt。最后一个参数是其他标志,用于指定文件属性。为了简单起见,我使用了 Win32 API 的 FILE_ATTRIBUTE_XXX 标志。

如果你只想获取目录名,并且是完整路径,代码将如下所示

win32_file_iterator itBegin("c:\\*", true, FILE_ATTRIBUTE_DIRECTORY);

很简单,对吧?

来源

#include <windows.h>
#include <iterator>
#include <string>

class win32_file_iterator : 
 public std::iterator<std::input_iterator_tag, std::string>
{
private:

 class internal_handle_data{
 public:
  internal_handle_data():_h(NULL), _ref(0){}
  void setHandle(HANDLE handle){ _h = handle; }
  HANDLE getHandle(){ return _h; }
  void incRef(){ _ref++; }
  unsigned decRef(){ return --_ref; }
  operator HANDLE(){ return _h; }

 private:
  HANDLE _h;
  unsigned _ref;
 };


public:

 win32_file_iterator(std::string strfilter, bool bFullPath = false, 
   int flag = FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_DIRECTORY):
   _bEnd(false), _bFullPath(bFullPath), _flag(flag){
        HANDLE h = ::FindFirstFile(strfilter.c_str(), &_wfd);
  _handle.setHandle(h);
  if(h == INVALID_HANDLE_VALUE){
   _bEnd = true;
  }else{
   _handle.incRef();
   std::string::size_type n1 = strfilter.find_last_of("\\");
   _strroot = strfilter.substr(0,n1+1);
   _chkvalid(_wfd);
  }
 }

 win32_file_iterator():_bEnd(true){}

 win32_file_iterator(win32_file_iterator& rhs){
  
  _handle = rhs._handle;
  _handle.incRef();
  _flag = rhs._flag;
  _bFullPath = rhs._bFullPath;
  _bEnd = rhs._bEnd;
  _wfd = rhs._wfd;
  _strfname = rhs._strfname;
  _strroot = rhs._strroot;  
 }

 ~win32_file_iterator(){
  if(_handle.decRef() == 0 && _handle.getHandle() != NULL ){
   FindClose(_handle);
  }
  
 }

 reference operator*(){
  return _strfname;
 }

 bool operator==(const win32_file_iterator& rhs) const{
  return (_bEnd == rhs._bEnd);
 }

 bool operator!=(const win32_file_iterator& rhs) const{
  return (_bEnd != rhs._bEnd);
 }


 win32_file_iterator& operator++(){
  _findnext();
  return *this;
 }

 win32_file_iterator& operator++(int){
  _findnext();
  return *this;
 }

private:

 void _findnext(){
  BOOL b = ::FindNextFile(_handle, &_wfd);
  if(b){
   _chkvalid(_wfd);
  }else{
   _bEnd = true;
  }
 }

 void _chkvalid(WIN32_FIND_DATA& _wfd){
  if(_wfd.dwFileAttributes & _flag){
   _getval(_wfd);
  }
  else{
   _findnext();
  }
 }

 void _getval(WIN32_FIND_DATA& wfd){
  if(_bFullPath)
   _strfname = _strroot+ wfd.cFileName;
  else
   _strfname = wfd.cFileName;
 }


private:
 int _flag;
 bool _bFullPath;
 bool _bEnd;
 internal_handle_data _handle;
 WIN32_FIND_DATA _wfd;
 std::string _strroot;
 std::string _strfname;
};

注释

代码可能有很多可怕的错误。但我想要展示的是我们可以使用类似迭代器的 STL 来查找文件名。希望对你有所帮助。你可以以任何方式使用这段代码,欢迎提出意见和建议。

另外,也请查看 boost::filesystem 库。它写得很好,但有点笨重。它需要一个额外的 DLL,我想。

© . All rights reserved.