Могу ли я использовать маску для итерации файлов в каталоге с помощью Boost?
Я хочу перебирать все файлы в каталоге, соответствующем чему-то вроде "somefiles*.формат txt." Имеет ли boost:: filesystem что-то встроенное для этого, или мне нужно регулярное выражение или что-то против каждого листа()?
7 ответов:
EDIT: как отмечено в комментариях, приведенный ниже код действителен для версий
boost::filesystem
до "В3". Для v3, обратитесь к предложениям в комментариях.
boost::filesystem
не имеет подстановочного поиска, вы должны фильтровать файлы самостоятельно.это пример кода, извлекающий содержимое каталога с помощью
boost::filesystem
' sdirectory_iterator
и фильтровать его сboost::regex
:const std::string target_path( "/my/directory/" ); const boost::regex my_filter( "somefiles.*\.txt" ); std::vector< std::string > all_matching_files; boost::filesystem::directory_iterator end_itr; // Default ctor yields past-the-end for( boost::filesystem::directory_iterator i( target_path ); i != end_itr; ++i ) { // Skip if not a file if( !boost::filesystem::is_regular_file( i->status() ) ) continue; boost::smatch what; // Skip if no match for V2: if( !boost::regex_match( i->leaf(), what, my_filter ) ) continue; // For V3: //if( !boost::regex_match( i->path().filename(), what, my_filter ) ) continue; // File matches, store it all_matching_files.push_back( i->leaf() ); }
(если вы ищете готовый к использованию класс с строением фильтрация каталогов, посмотрите на Qt
QDir
.)
есть
Boost Range Adaptors
путь:#define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0 #include <boost/filesystem.hpp> #include <boost/range/adaptors.hpp> namespace bfs = boost::filesystem; namespace ba = boost::adaptors; const std::string target_path( "/my/directory/" ); const boost::regex my_filter( "somefiles.*\.txt" ); boost::smatch what; for (auto &entry: boost::make_iterator_range(bfs::directory_iterator(target_path), {}) | ba::filtered(static_cast<bool (*)(const bfs::path &)>(&bfs::is_regular_file)) | ba::filtered([&](const bfs::path &path){ return boost::regex_match(path.filename().string(), what, my_filter); }) ) { // There are only files matching defined pattern "somefiles*.txt". std::cout << entry.path().filename() << std::endl; }
мое решение по существу такое же, как Julien-L, но инкапсулированное в файле include, его лучше использовать. Реализовано с помощью boost:: filesystem v3. Я думаю, что что-то вроде этого не входит в файловую систему boost::напрямую, потому что это приведет к зависимости от boost::regex.
#include "FilteredDirectoryIterator.h" std::vector< std::string > all_matching_files; std::for_each( FilteredDirectoryIterator("/my/directory","somefiles.*\.txt"), FilteredDirectoryIterator(), [&all_matching_files](const FilteredDirectoryIterator::value_type &dirEntry){ all_matching_files.push_back(dirEntry.path()); } );
альтернативно используйте FilteredRecursiveDirectoryIterator для рекурсивного поиска подкаталогов:
#include "FilteredDirectoryIterator.h" std::vector< std::string > all_matching_files; std::for_each( FilteredRecursiveDirectoryIterator("/my/directory","somefiles.*\.txt"), FilteredRecursiveDirectoryIterator(), [&all_matching_files](const FilteredRecursiveDirectoryIterator::value_type &dirEntry){ all_matching_files.push_back(dirEntry.path()); } );
FilteredDirectoryIterator.h
#ifndef TOOLS_BOOST_FILESYSTEM_FILTEREDDIRECTORYITERATOR_H_ #define TOOLS_BOOST_FILESYSTEM_FILTEREDDIRECTORYITERATOR_H_ #include "boost/filesystem.hpp" #include "boost/regex.hpp" #include <functional> template <class NonFilteredIterator = boost::filesystem::directory_iterator> class FilteredDirectoryIteratorTmpl : public std::iterator< std::input_iterator_tag, typename NonFilteredIterator::value_type > { private: typedef std::string string; typedef boost::filesystem::path path; typedef std::function< bool(const typename NonFilteredIterator::value_type &dirEntry) > FilterFunction; NonFilteredIterator it; NonFilteredIterator end; const FilterFunction filter; public: FilteredDirectoryIteratorTmpl(); FilteredDirectoryIteratorTmpl( const path &iteratedDir, const string ®exMask ); FilteredDirectoryIteratorTmpl( const path &iteratedDir, const boost::regex &mask ); FilteredDirectoryIteratorTmpl( const path &iteratedDir, const FilterFunction &filter ); //preincrement FilteredDirectoryIteratorTmpl<NonFilteredIterator>& operator++() { for(++it;it!=end && !filter(*it);++it); return *this; }; //postincrement FilteredDirectoryIteratorTmpl<NonFilteredIterator> operator++(int) { for(++it;it!=end && !filter(*it);++it); return FilteredDirectoryIteratorTmpl<NonFilteredIterator>(it,filter); }; const boost::filesystem::directory_entry &operator*() {return *it;}; bool operator!=(const FilteredDirectoryIteratorTmpl<NonFilteredIterator>& other) { return it!=other.it; }; bool operator==(const FilteredDirectoryIteratorTmpl<NonFilteredIterator>& other) { return it==other.it; }; }; typedef FilteredDirectoryIteratorTmpl<boost::filesystem::directory_iterator> FilteredDirectoryIterator; typedef FilteredDirectoryIteratorTmpl<boost::filesystem::recursive_directory_iterator> FilteredRecursiveDirectoryIterator; template <class NonFilteredIterator> FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl() : it(), filter( [](const boost::filesystem::directory_entry& /*dirEntry*/){return true;} ) { } template <class NonFilteredIterator> FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl( const path &iteratedDir,const string ®exMask ) : FilteredDirectoryIteratorTmpl(iteratedDir, boost::regex(regexMask)) { } template <class NonFilteredIterator> FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl( const path &iteratedDir,const boost::regex ®exMask ) : it(NonFilteredIterator(iteratedDir)), filter( [regexMask](const boost::filesystem::directory_entry& dirEntry){ using std::endl; // return false to skip dirEntry if no match const string filename = dirEntry.path().filename().native(); return boost::regex_match(filename, regexMask); } ) { if (it!=end && !filter(*it)) ++(*this); } template <class NonFilteredIterator> FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl( const path &iteratedDir, const FilterFunction &filter ) : it(NonFilteredIterator(iteratedDir)), filter(filter) { if (it!=end && !filter(*it)) ++(*this); } #endif
Я считаю, что directory_iterators будет предоставлять только все файлы в каталоге. Это до вас, чтобы фильтровать их по мере необходимости.
принятый ответ не компилировался для меня даже тогда, когда я использовал
i->path().extension()
вместоleaf()
. То, что сработало для меня, было примером из этот сайт. Вот код, измененный, чтобы применить фильтр:vector<string> results; filesystem::path filepath(fullpath_to_file); filesystem::directory_iterator it(filepath); filesystem::directory_iterator end; const boost::regex filter("myfilter(capturing group)"); BOOST_FOREACH(filesystem::path const &p, make_pair(it, end)) { if(is_regular_File(p)) { match_results<string::const_iterator> what; if (regex_search(it->path().filename().string(), what, pidFileFilter, match_default)) { string res = what[1]; results.push_back(res); } } }
Я использую версию Boost: 1.53.0.
Почему мы все просто не используем
glob()
и некоторые регулярные выражения вне меня.
Как уже упоминалось в конце Жюльен-LС должности
QDir
- Это именно то, что вы хотите.
https://qt-project.org/doc/qt-5.0/qtcore/qdir.html#QDir-3
Я искал решение для этого ранее, и я думаю, что мое решение является самым простым
#include <boost/filesystem.hpp> #include <boost/regex.hpp> #include <boost/iterator/iterator_facade.hpp> #include <boost/exception/all.hpp> struct dir_filter_iter : public boost::iterator_facade< dir_filter_iter, boost::filesystem::path, boost::forward_traversal_tag, boost::filesystem::path > { using path = boost::filesystem::path; using impl_type = boost::filesystem::directory_iterator; dir_filter_iter():impl_(){} dir_filter_iter(path p, boost::regex rgx):impl_(std::move(p)),rgx_(std::move(rgx)){ namespace bf = boost::filesystem; if( ! bf::is_directory(p) ){ BOOST_THROW_EXCEPTION( boost::enable_error_info(std::domain_error("not a dir")) << boost::errinfo_file_name(p.string())); } } private: friend class boost::iterator_core_access; bool equal(const dir_filter_iter& that)const{ return this->impl_ == that.impl_; } void increment(){ assert( impl_ != impl_type() ); for(;;){ ++impl_; if( impl_ == impl_type() ) break; std::string s(impl_->path().string()); if( boost::regex_match( s, rgx_ ) ){ break; } } } path dereference()const{ assert( impl_ != impl_type() ); return *impl_; } impl_type impl_; boost::regex rgx_; }; struct dir_filter_iter_maker{ using value_type = dir_filter_iter; explicit dir_filter_iter_maker(boost::regex rgx):rgx_(rgx){} value_type make()const{ return value_type(); } value_type make(boost::filesystem::path p)const{ return value_type(std::move(p),rgx_); } template<typename... Args> auto operator()(Args&&... args)->decltype(make(args...)){ return this->make(std::forward<Args>(args)...); } private: boost::regex rgx_; };
затем вы можете сделать
dir_filter_iter_maker di_maker(boost::regex(R"_(.*\.hpp)_")); std::for_each( di_maker(p), di_maker(), [](const bf::path& p){std::cout << p.string() << "\n";});