마스크를 사용하여 Boost로 디렉터리의 파일을 반복 할 수 있습니까?
같은 디렉토리에있는 모든 파일을 반복하고 싶습니다 somefiles*.txt
.
boost::filesystem
이를 수행하기 위해 내장 된 것이 있습니까 , 아니면 각각에 대해 정규식이나 무언가가 필요 leaf()
합니까?
편집 : 주석에서 언급했듯이 아래 코드는 boost::filesystem
v3 이전 버전에 유효합니다 . v3의 경우 의견의 제안을 참조하십시오.
boost::filesystem
와일드 카드 검색이 없으므로 파일을 직접 필터링해야합니다.
이것은있는 디렉토리의 내용을 추출하는 코드 샘플입니다 boost::filesystem
'들 directory_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().string(), 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과 동일하지만 포함 파일에 캡슐화되어 사용하는 것이 더 좋습니다. boost :: filesystem v3을 사용하여 구현되었습니다. boost :: regex에 대한 종속성을 도입하기 때문에 boost :: filesystem에 직접 포함되지 않은 것 같습니다.
#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을 사용하고 있습니다.
Why we don't all just use glob()
and some regex is beyond me.
As mentioned at the end of Julien-L's post QDir
is exactly what you want.
https://qt-project.org/doc/qt-5.0/qtcore/qdir.html#QDir-3
I was looking for a solution to this earlier and I think my solution is the simplest
#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_;
};
Then you can do
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";});
ReferenceURL : https://stackoverflow.com/questions/1257721/can-i-use-a-mask-to-iterate-files-in-a-directory-with-boost
'code' 카테고리의 다른 글
언제 StringBuilder.AppendLine / string.Format과 StringBuilder.AppendFormat을 사용합니까? (0) | 2020.12.25 |
---|---|
JavaScript는 지역 변수로 클로저를 지원하지 않습니까? (0) | 2020.12.25 |
git은 바이너리 파일을 어떻게 처리합니까? (0) | 2020.12.25 |
Vim의 탭 및 백 스페이스 동작으로서의 공백 (0) | 2020.12.25 |
Entity Framework 코드 첫 번째 AddOrUpdate 메서드 삽입 중복 값 (0) | 2020.12.25 |