una txt texto manejo listar libreria leer guardar fichero estructura dirent directorios directorio dentro datos crear carpeta archivos archivo c++ boost filesystems

c++ - txt - ¿Puedo usar una máscara para iterar archivos en un directorio con Boost?



listar archivos dentro de un directorio o carpeta en c (7)

Quiero iterar sobre todos los archivos en un directorio que coincida con algo como "somefiles * .txt". ¿Impulsa :: el sistema de archivos tiene algo incorporado para hacer eso, o necesito una expresión regular o algo en contra de cada hoja ()?



Creo que directory_iterators solo proporcionará todos los archivos en un directorio. Depende de usted filtrarlos según sea necesario.


Estaba buscando una solución a esto antes y creo que mi solución es la más simple

#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_; };

Entonces puedes hacer

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";});


Hay una forma de 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; }


La respuesta aceptada no compiló para mí incluso cuando utilicé i->path().extension() lugar de leaf() . Lo que funcionó para mí fue un ejemplo de este sitio web . Aquí está el código, modificado, para aplicar un filtro:

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); } } }

Estoy usando la versión de Boost: 1.53.0.

Por qué no todos solo usamos glob() y algunas expresiones regulares están más allá de mí.


Mi solución es esencialmente la misma que Julien-L, pero encapsulada en el archivo de inclusión es más fácil de usar. Implementado usando boost :: filesystem v3. Supongo que algo así no está incluido directamente en el sistema de archivos boost :: porque introduciría dependencia en 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()); } );

alternativamente use FilteredRecursiveDirectoryIterator para la búsqueda recursiva de subdirectorios:

#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 &regexMask ); 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 &regexMask ) : FilteredDirectoryIteratorTmpl(iteratedDir, boost::regex(regexMask)) { } template <class NonFilteredIterator> FilteredDirectoryIteratorTmpl<NonFilteredIterator>::FilteredDirectoryIteratorTmpl( const path &iteratedDir,const boost::regex &regexMask ) : 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


EDITAR : Como se indica en los comentarios, el código siguiente es válido para las versiones de boost::filesystem anterior a v3. Para v3, consulte las sugerencias en los comentarios.

boost::filesystem no tiene búsqueda de comodines, usted debe filtrar los archivos usted mismo.

Este es un ejemplo de código que extrae el contenido de un directorio con un directorio de directorio boost::filesystem y lo filtra con 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() ); }

(Si está buscando una clase lista para usar con un filtro de directorios incorporado, eche un vistazo al QDir de Qt).