Win32 文件名迭代(STL 方式)






4.96/5 (18投票s)
2004年11月21日
1分钟阅读

142344

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,我想。