Win32 file name iteration STL way






4.96/5 (18 votes)
Nov 21, 2004
1 min read

137354

669
This simple class shows how to iterate file names by using STL iterator interface.
Introduction
Several times I worked with file names, I usually used Win32 API such as ::FindFirstFile
.. But it turns out that it's so boring work. Finally, I realized I can use STL's great feature, iterator, to handle file name iteration. That's why I made a simple STL iterator class for file name iteration.
Usage
win32_file_iterator itBegin("c:\\*.*"), itEnd; std::copy(itBegin, itEnd, ostream_iterator<std::string>(cout, "\n"));
The code above shows the simplest way to use the class. Actually, you can use almost all of STL algorithm, I think..
win32_file_iterator itBegin("c:\\*.*"), itEnd;
std::vector<std::string> vec(itBegin, itEnd);
You also can fill the STL container by using the constructor that takes begin iterator and end iterator.
Actually, win32_file_iterator
class' constructor takes three parameters. The first one is the filter string that is for calling ::FindFirstFile
function. Second one is the flag that specifies whether dereferenced path is full path or not. For example, if it's true, the returned path string is c:\test\aa.txt, otherwise it'll be aa.txt only. The last parameter is the other flags which specify file attribute. For simplicity, I used Win32 API's FILE_ATTRIBUTE_XXX
flags..
If you want to get only directory names, and which is full path, the code will look like this:
win32_file_iterator itBegin("c:\\*", true, FILE_ATTRIBUTE_DIRECTORY);
So easy, huh?
Source
#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; };
Comment
The code might have many terrible bugs. But what I want was to show the way we can use STL like iteration to find filenames. I wish it'll help you. You can use this code in whatever ways you want, comments are welcome..
And also check out boost::filesystem
library.. it's well-written but a little bit heavy. It needs an additional DLL, I suppose.