返回   cpper编程论坛 > 技术杂烩
注册账号 论坛帮助 会员列表 日历事件 搜索 今日新帖 标记版面已读

技术杂烩 找不到地方的技术问题?这里!

回复
 
LinkBack 主题工具 显示模式
  #1 (permalink)  
旧 2004-05-31
高级会员
 
注册日期: 2002-09-16
帖子: 1,087
文章: 1
SpitFire 正向着好的方向发展
默认 搜索文件的iterator

目前要改进的地方是每个目录要search两次,原因是windows下没有有类似unix的fnmatch函数,如果有的话只用一次了.已经测试过的平台(公司有的平台)
1.windows2000(其它没测试)
2.redhat linux 9.0
3.IBM AIX 4.3.3
4.HP UNIX 11i v2(内部版本 11.23)

如果大家有其它的环境(各种不同的linux,sco unix,suse linux),也可以进行一下测试

findfile.cpp(测试用的cpp文件)
代码:
#include "FindFileContainer.h" #include <vector> #include <iterator> #include <algorithm> #include <iostream> #include <functional> using namespace std; struct CompareFileName : public unary_function<file_info,bool> { CompareFileName(const string& name):name_(name){} bool operator()(const file_info& lrs) const { if (lrs.name() > name_) return true; return false; } private: string name_; }; ostream& operator<<(ostream& os,const file_info& fileinfo) { if (fileinfo.issubdirectory()) { os << "D\t"; } else { os << "F\t"; } os << fileinfo.dir() << fileinfo.name(); return os; } // STL not have copy_if function,just have remove_copy_if, we can // use remove_copy_if to implement copy_if template<typename InputIterator, typename OutputIterator, typename Pred> OutputIterator copy_if(InputIterator first,InputIterator last,OutputIterator result,Pred pred) { return remove_copy_if(first,last,result,not1(pred)); } //findfile path pattern case-i int main(int argc,char* argv[]) { if ( argc != 4) { printf("usage:findfile path pattern case-i\n"); return 1; } bool ci = (argv[3][0] == '1'); FindFileContainer findfile(argv[1],argv[2],both,true,ci); FindFileContainer::iterator begin = findfile.begin(); FindFileContainer::iterator end = findfile.end(); copy_if(begin,end,ostream_iterator<file_info>(cout,"\n"),CompareFileName("A")); return 0; }
FindFileContainer.h (文件容器的头文件)
代码:
/* Name: FindFileContainer.h Author: papercrane(Heheng Li) ,spitfire(HuanMing Zheng) Description: Iterate files recursively Date: 2003.06.11 Copyright: 2003 papercrane 2004 spitfire,papercrane Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. Version: 1.1 Last update: 2004.05.26 */ #ifndef FINDFILECONTAINER_H_ #define FINDFILECONTAINER_H_ #include <string> #include "FindFileWrapper.h" class FindFileContainer { public: class iterator; FindFileContainer( const std::string& basepath = "", // base path to start iteration const std::string& object = "*.*", // object file name pattern searchmode mode = fileonly, // one of searchmode bool recurse = false, // need to find in subdirectory? bool insensitively = false, // case-insensitively ,in windows,this agrument not use char delim = pathdelim); ~FindFileContainer(); iterator begin(); iterator end(); class iterator { public: friend class FindFileContainer; friend class file_info; typedef file_info value_type; typedef int difference_type; typedef file_info* pointer; typedef file_info& reference; typedef const file_info* const_pointer; typedef const file_info& const_reference; typedef std::input_iterator_tag iterator_category; iterator(); iterator& operator++(); iterator operator++(int); bool operator==(const iterator& other); bool operator!=(const iterator& other); const_reference operator*(); const_pointer operator->(); private: explicit iterator(FindFileContainer* self); explicit iterator(int); enum status {s_normal,s_end,s_null}; FindFileContainer* container_; status status_; int count_; }; private: friend class iterator; FindFileWrapper find_; FindFileContainer(const FindFileContainer&); FindFileContainer& operator=(const FindFileContainer&); }; #endif // defined(FINDFILECONTAINER_H_)
FindFileContainer.cpp
代码:
// FindFileContainer.cpp /* Name: FindFileContainer.cpp Author: papercrane(Heheng Li) ,spitfire(HuanMing Zheng) Description: Implementation for FindFileContainer.h Date: 2003.06.11 Copyleft: 2003 papercrane 2004 spitfire,papercrane Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. Version: 1.1 Last update: 2004.05.26 */ #include "FindFileContainer.h" using std::string; FindFileContainer::FindFileContainer(const string& basepath, const string& object, searchmode mode, bool recurse,bool insensitively, char delim) : find_(basepath,object,mode,recurse,insensitively,delim) { } FindFileContainer::~FindFileContainer(void) { } FindFileContainer::iterator FindFileContainer::begin() { iterator p(this); return p; } FindFileContainer::iterator FindFileContainer::end() { iterator p(1); return p; } //the default ctor FindFileContainer::iterator::iterator():container_(NULL),status_(s_null),count_(-1) { } //this ctor create a end iterator,it's private ctor FindFileContainer::iterator::iterator(int):container_(NULL),status_(s_end),count_(-1) { } //this ctor create a begin iterator,it't private ctor FindFileContainer::iterator::iterator(FindFileContainer* self):container_(self),status_(s_null),count_(0) { status_ = s_normal; container_->find_.start_find(); if (container_->find_.is_end()) { status_ = s_end; } else { status_ = s_normal; count_ = 1; } } bool FindFileContainer::iterator::operator==(const FindFileContainer::iterator& other) { if(status_ == s_end && status_ == other.status_) return true; return false; } bool FindFileContainer::iterator::operator!=(const FindFileContainer::iterator& other) { return !operator==(other); } FindFileContainer::iterator& FindFileContainer::iterator::operator++() { if (status_ == s_null) { throw FindIteratorError("use a NULL FindFileContainer::iterator"); } container_->find_.find_next(); if (container_->find_.is_end()) { status_ = s_end; } else { status_ = s_normal; ++count_; } return *this; } FindFileContainer::iterator FindFileContainer::iterator::operator++(int) { iterator tmp = *this; operator++(); return tmp; } const file_info& FindFileContainer::iterator::operator*() { return container_->find_.getfileinfo(); } const file_info* FindFileContainer::iterator::operator->() { return &container_->find_.getfileinfo(); }
FindFileWrapper.h (隔离不同平台的find实现)
代码:
/* Name: FindFileWrapper.h Author: papercrane(Heheng Li) ,spitfire(HuanMing Zheng) Description: Iterate files recursively Date: 2003.06.11 Copyleft: 2003 papercrane 2004 spitfire,papercrane Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. Version: 1.1 Last update: 2004.05.31 */ #ifndef FINDFILEWRAPPER_H_ #define FINDFILEWRAPPER_H_ enum searchmode { fileonly, dironly, both }; #ifdef _WIN32 #ifdef _MSC_VER #pragma warning(disable:4786) #endif #include <io.h> typedef unsigned int attrib_t; const char pathdelim = '\\'; struct finddata { long handle; _finddata_t find_t; }; #else #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> const char pathdelim = '/'; struct finddata { DIR* dir; struct dirent* dirent_t; struct stat statbuf; }; typedef mode_t attrib_t; #endif #include <list> #include <string> #include <stdexcept> class FindIteratorError : public std::runtime_error { public: FindIteratorError(const std::string& s):runtime_error(s){} }; class file_info { public: file_info() :issubdirectory_(false), attrib_(0),time_create_(0), time_access_(0), time_write_(0), size_(0),name_(""), dir_("") { } bool issubdirectory(void) const { return issubdirectory_; } attrib_t attrib(void) const { return attrib_; } time_t createtime(void) const { return time_create_; } time_t accesstime(void) const { return time_access_; } time_t writetime(void) const { return time_write_; } size_t size(void) const { return size_; } const std::string& name() const { return name_; } const std::string& dir() const { return dir_; } private: friend class FindFileWrapper; bool issubdirectory_; attrib_t attrib_; time_t time_create_; time_t time_access_; time_t time_write_; size_t size_; std::string name_; std::string dir_; }; class FindFileWrapper { public: FindFileWrapper( const std::string& basepath, // base path to start iteration const std::string& object, // object file name pattern searchmode mode , // one of searchmode bool recurse, // need to find in subdirectory? bool insensitively, // case-insensitively ,in windows,this agrument not use char delim ); ~FindFileWrapper(); void start_find(void); bool is_end(void) const; void find_next(void); const file_info& getfileinfo(); private: void dir(std::string& s) const; // reset the state for iteration void reset(void); // put all subdirs into the stack void pushsubdirs(const std::string& path); // pop up a subdir from the stack void popsubdir(std::string& path); // search in subdirs for files void findinsubdir(); // find a file in the path given bool findonefile(bool start); // set full name of current path void setcurpath(); // is file found proper to return bool suitableforsearchmode(void) const; // no more files in current path bool nomorefile(void) const; // no more subdirs in the stack bool nomoresubdir(void) const; std::string basepath_; // base path std::string object_; // object file name pattern, wildcard permitted int searchmode_; // one of searchmode bool recurse_; // need to find in subdirectory? const char delim_; // char to seperate the path bool insensitively_; finddata finddata_; // file find data for C CRT API file_info file_info_; std::string cursubdir_; // subdir full path iterated currently typedef std::list<std::string> dirstack; dirstack subdirs_; // stack storing subdirs(full name) to be visited }; #endif // defined(FINDFILEWRAPPER_H_)
FindFileWrapper.cpp
代码:
/* Name: FindFileWraper.cpp Author: papercrane(Heheng Li) ,spitfire(HuanMing Zheng) Description: Implementation for FindFileWrapper.h Date: 2003.06.11 Copyleft: 2003 papercrane 2004 spitfire,papercrane Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. Version: 1.1 Last update: 2004.05.31 */ #include "FindFileWrapper.h" #include <cassert> #include <cstring> using std::string; using std::list; inline void normalizepath(string& path, char delim) { // make sure it's delim-end except null path // \ or / differs from null as base path, // where \ or / indicates root directory // and null indicates current directory int len = path.length(); if(len > 0 && path[len - 1] != delim) path.append(1,delim); } #ifdef _WIN32 namespace { const long invalid_search_handle = -1L; const int end_search = -1; const char* any_mask = "*.*"; const bool START = true; const bool CONTINUE = false; void init_finddata(finddata& data) { memset(&data,0,sizeof(data)); data.handle = invalid_search_handle; } void my_find_close(finddata& data) { if (data.handle != invalid_search_handle) { _findclose(data.handle); data.handle = invalid_search_handle; memset(&data.find_t,0,sizeof(data.find_t)); } } bool my_find_first(const string& path,const string& pattern,finddata& data,bool insensitively ) { string find = path + pattern; data.handle = _findfirst(find.c_str(),&data.find_t); if (data.handle == invalid_search_handle) { return false; } return true; } bool my_find_next(const string& path,const string& pattern,finddata& data,bool insensitively ) { assert(data.handle != invalid_search_handle); if (_findnext(data.handle,&data.find_t) == end_search) { my_find_close(data); return false; } return true; } inline bool my_is_close(const finddata& data) { return data.handle == invalid_search_handle; } inline bool my_is_subdir(const finddata& data) { return (data.find_t.attrib & _A_SUBDIR) != 0; } inline attrib_t my_attrib(const finddata& data) { return data.find_t.attrib; } inline time_t my_time_create(const finddata& data) { return data.find_t.time_create; } inline time_t my_time_access(const finddata& data) { return data.find_t.time_access; } inline time_t my_time_write(const finddata& data) { return data.find_t.time_write; } inline int my_size(const finddata& data) { return data.find_t.size; } inline const char* my_name(const finddata& data) { return data.find_t.name; } inline bool my_isspecialfile(const finddata& data) { // pay attention, if argument 3 is replaced by 1 in first call, // data.name as ".*" will generate 0 as result, which may cause // defect, while if replaced by 2 in second call, "..*" may also // make trouble here return strncmp(data.find_t.name,".",2) == 0 || strncmp(data.find_t.name,"..",3) == 0; } } #else //if not windows os #include <fnmatch.h> #include <limits.h> #include <algorithm> #include <unistd.h> namespace { //if not support S_ISLNK marco,define it //if not support link file (no define S_IFLNK),define S_ISLNK return false; #ifdef S_IFLNK #ifndef S_ISLNK #define S_ISLNK(mode) (((mode)& S_IFMT) == S_IFLNK) #endif //end ifndef S_ISLNK #else //not define S_IFLNK #define S_ISLNK(mode) (1==0) #endif //end ifdef S_IFLNK //if os not support S_ISDIR marco,define it #ifndef S_ISDIR #define S_ISDIR(mode) (((mode)& S_IFMT) == S_IFDIR) #endif const char* any_mask = "*"; const bool START = true; const bool CONTINUE = false; const int PATH_MAX_GUESS = 2048; int get_path_max() // { int pathmax = 0; if((pathmax=pathconf("/",_PC_PATH_MAX)) < 0) { pathmax = PATH_MAX_GUESS; } else { ++pathmax; } return pathmax; } class PathAlloc { public: PathAlloc():block_(new char[get_path_max()]) { } ~PathAlloc() { if (block_) { delete []block_; } } char* getblock() const {return block_;} private: char* block_; }; bool matchfile(const char* pattern,const char* filename,bool insensitively) { #ifdef FNM_CASEFOLD //FNM_CASEFOLD flag is GNU extensions. int flag = 0; if (insensitively) flag = FNM_CASEFOLD; return fnmatch(pattern,filename,flag); #else if (insensitively) //case-insensitively { static PathAlloc patternbuffer; static PathAlloc filenamebuffer; static int pathmax = get_path_max(); unsigned int patternsize = strlen(pattern); unsigned int filenamesize = strlen(filename); assert(patternsize <= pathmax); assert(filenamesize <= pathmax); std::transform(pattern,pattern+patternsize,patternbuffer.getblock(),toupper); std::transform(filename,filename+filenamesize,filenamebuffer.getblock(),toupper); patternbuffer.getblock()[patternsize] = '\0'; filenamebuffer.getblock()[filenamesize] = '\0'; return fnmatch(patternbuffer.getblock(),filenamebuffer.getblock(),0); } else { return fnmatch(pattern,filename,0); } #endif } void init_finddata(finddata& data) { memset(&data,0,sizeof(data)); } void my_find_close(finddata& data) { if (data.dir) { closedir(data.dir); data.dir = NULL; } } bool my_find_first(const string& path,const string& pattern,finddata& data,bool insensitively) { data.dir = opendir(path.c_str()); if (NULL == data.dir) { return false; } while((data.dirent_t = readdir(data.dir)) != NULL) { if (matchfile(pattern.c_str(),data.dirent_t->d_name,insensitively) == 0) { string fullname = path + data.dirent_t->d_name; lstat(fullname.c_str(),&data.statbuf); return true; } } my_find_close(data); return false; } bool my_find_next(const string& path,const string& pattern,finddata& data,bool insensitively) { assert(data.dir != NULL); while((data.dirent_t = readdir(data.dir)) != NULL) { if (matchfile(pattern.c_str(),data.dirent_t->d_name,insensitively) == 0) { string fullname = path + data.dirent_t->d_name; lstat(fullname.c_str(),&data.statbuf); return true; } } my_find_close(data); return false; } bool my_is_close(const finddata& data) { return data.dir == NULL; } bool my_is_subdir(const finddata& data) { return S_ISDIR(data.statbuf.st_mode) && !S_ISLNK(data.statbuf.st_mode); } attrib_t my_attrib(const finddata& data) { return data.statbuf.st_mode; } time_t my_time_create(const finddata& data) { return data.statbuf.st_ctime; } time_t my_time_access(const finddata& data) { return data.statbuf.st_atime; } time_t my_time_write(const finddata& data) { return data.statbuf.st_mtime; } int my_size(const finddata& data) { return data.statbuf.st_size; } const char* my_name(const finddata& data) { return data.dirent_t->d_name; } bool my_isspecialfile(const finddata& data) { // pay attention, if argument 3 is replaced by 1 in first call, // data.name as ".*" will generate 0 as result, which may cause // defect, while if replaced by 2 in second call, "..*" may also // make trouble here return strncmp(data.dirent_t->d_name,".",2) == 0 || strncmp(data.dirent_t->d_name,"..",3) == 0; } } #endif FindFileWrapper::FindFileWrapper(const string& basepath, const string& object, searchmode mode, bool recurse,bool insensitively, char delim) : basepath_(basepath), object_(object), searchmode_(mode), recurse_(recurse), delim_(delim),insensitively_(insensitively) { // append delim to base path if necessary normalizepath(basepath_,delim_); init_finddata(finddata_); } FindFileWrapper::~FindFileWrapper(void) { // shut down the file find handle my_find_close(finddata_); } void FindFileWrapper::dir(string& s) const { s = cursubdir_; } void FindFileWrapper::start_find(void) { // shut down last opened file find handle reset(); cursubdir_ = basepath_; // initialize depth-first searching if(recurse_) pushsubdirs(basepath_); // find one available file in base path if(findonefile(START)) return; // try in subdirectories if(recurse_) findinsubdir(); } bool FindFileWrapper::is_end(void) const { return nomorefile() && nomoresubdir(); } void FindFileWrapper::find_next(void) { // new subdirectory currently visited will be retrieved // durring findinsubdir() in begin() or operator++() // in recurse iteration, or durring findonefile(const string&) // in begin() in both iterations // find one available file in current path if(findonefile(CONTINUE)) return; // if not found, try in subdirectories if(recurse_) findinsubdir(); } void FindFileWrapper::reset(void) { // shut down file find handle my_find_close(finddata_); subdirs_.clear(); } void FindFileWrapper::pushsubdirs(const string& path) { finddata data; // quit if no files or subdirectories at all if(!my_find_first(path,any_mask,data,insensitively_)) return; dirstack newsubdirs; do { // some os tells . and .. is subdirectory, // but static method issubdir shows they aren't, // for safety, check anyway if(my_is_subdir(data) && !my_isspecialfile(data)) newsubdirs.push_back(path + my_name(data) + delim_); } while(my_find_next(path,any_mask,data,insensitively_)); // push as stack, so if ascending order is perferred, // it should be sorted in descending order // newsubdirs.sort(std::greater<string>()); // push into real stack subdirs_.splice(subdirs_.end(),newsubdirs); } inline void FindFileWrapper::popsubdir(string& path) { // peek and pop up path = subdirs_.back(); subdirs_.pop_back(); } void FindFileWrapper::findinsubdir(void) { // depth-first searching while(!subdirs_.empty()) { popsubdir(cursubdir_); pushsubdirs(cursubdir_); // search current subdirectory for files if(findonefile(START)) break; } } bool FindFileWrapper::findonefile(bool start) { if(start) { // no files or subdirectories matched at all if(!my_find_first(cursubdir_,object_,finddata_,insensitively_)) return false; while(true) { // some os tells . and .. is subdirectory, if(!my_isspecialfile(finddata_) && suitableforsearchmode()) return true; if(!my_find_next(cursubdir_,object_,finddata_,insensitively_)) { return false; } } } bool findover = true; // find next file until available found or searching ended while(my_find_next(cursubdir_,object_,finddata_,insensitively_)) { if(suitableforsearchmode()) { findover = false; break; } } if(findover) { my_find_close(finddata_); } return !findover; } bool FindFileWrapper::suitableforsearchmode(void) const { switch(searchmode_) { case fileonly: return !my_is_subdir(finddata_); case dironly: return my_is_subdir(finddata_); case both: return true; default: assert(false); return false; } } inline bool FindFileWrapper::nomorefile(void) const { return my_is_close(finddata_); } inline bool FindFileWrapper::nomoresubdir(void) const { return !recurse_ || subdirs_.empty(); } const file_info& FindFileWrapper::getfileinfo() { file_info_.issubdirectory_ = my_is_subdir(finddata_); file_info_.attrib_ = my_attrib(finddata_); file_info_.time_create_ = my_time_create(finddata_); file_info_.time_access_ = my_time_access(finddata_); file_info_.time_write_ = my_time_write(finddata_); file_info_.size_ = my_size(finddata_); file_info_.name_ = my_name(finddata_); dir(file_info_.dir_); return file_info_; }
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #2 (permalink)  
旧 2004-06-01
高级会员
 
注册日期: 2002-10-26
帖子: 125
papercrane 正向着好的方向发展
发送 MSN 消息给 papercrane
默认

很好。只是能不能在FindFileContainer使用pimple模式,然后把finddata和FindFileWrapper等与客户无关的东西全放到cpp中呢?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #3 (permalink)  
旧 2004-06-01
高级会员
 
注册日期: 2002-09-16
帖子: 1,087
文章: 1
SpitFire 正向着好的方向发展
默认

hoho,编译防火墙,有过这个想法,不过当时为了写码方便,而且这个东西应该不会有太多的变化,因为实现的差别在于平台的差别,平台的具体实现其实就在FindFileWrapper.cpp中,可以考虑将finddata改为引用或是指针,以降低编译关联。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
回复

书签

主题工具
显示模式

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子

启用 BB 代码
论坛启用 表情符号
论坛启用 [IMG] 代码
论坛禁用 HTML 代码
Trackbacks are 启用
Pingbacks are 启用
Refbacks are 启用



所有时间均为格林尼治时间 +9。现在的时间是 07:53 AM


Powered by vBulletin® 版本 3.7.0
版权所有 ©2000 - 2009,Jelsoft Enterprises Ltd.
(C) Copy Right All Right Reserved 2001 - 2007

Search Engine Friendly URLs by vBSEO 3.1.0