Ich möchte über alle Dateien in einem Verzeichnis mit "somefiles * .txt" iterieren. Hat Boost :: Dateisystem etwas eingebaut, oder brauche ich eine Regex oder etwas gegen jedes Blatt()?Kann ich eine Maske verwenden, um Dateien in einem Verzeichnis mit Boost zu iterieren?
Antwort
BEARBEITEN: Wie in den Kommentaren erwähnt, ist der folgende Code für Versionen von boost::filesystem
vor v3 gültig. Lesen Sie für v3 die Vorschläge in den Kommentaren.
boost::filesystem
nicht Wildcard-Suche hat, haben Sie Dateien selbst zu filtern.
Dies ist ein Beispielcode, den Inhalt eines Verzeichnisses mit einer boost::filesystem
‚s Extrahieren directory_iterator
und Filtrieren mit 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());
}
(Wenn Sie sich für eine ready-to-use-Klasse mit builtin-Verzeichnis Filterung, werfen Sie einen Blick auf Qt QDir
.)
Ich glaube, das Verzeichnis_iterators wird nur alle Dateien in einem Verzeichnis bereitstellen. Es liegt an Ihnen, sie nach Bedarf zu filtern.
Wie bereits am Ende der Julien-L 's Post QDir
ist genau das, was Sie wollen.
https://qt-project.org/doc/qt-5.0/qtcore/qdir.html#QDir-3
Meine Lösung ist im Wesentlichen der gleiche wie Julien-L, aber in der Include-Datei verkapselt ist es schöner zu verwenden. Implementiert mit boost :: Dateisystem v3. Ich nehme an, dass so etwas nicht direkt im boost :: Dateisystem enthalten ist, da es eine Abhängigkeit von boost :: regex erzeugen würde.
#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());
}
);
alternativ FilteredRecursiveDirectoryIterator für die Suche rekursiv Unterverzeichnisse verwenden:
#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
Es gibt eine Boost Range Adaptors
Weg ist:
#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;
}
Gut eins! Range Adapter zur Rettung. – berkus
Für diejenigen, die heutzutage darauf stoßen: std :: regex_match sowie boost :: regex_match akzeptieren keine temporäre Zeichenfolge mehr. Für das obige Beispiel bedeutet dies, dass der Lambda-Text an etwas wie auto oFile = Pfad, Dateiname() angepasst werden muss. String(); gib xxx :: regex_match zurück (oFile, ...). – gilgamash
Ich war auf der Suche nach einer Lösung für dieses früher und ich denke, dass meine Lösung die einfachste ist
#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_;
};
Dann können Sie
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";});
Die akzeptierte Antwort für mich selbst kompilieren nicht tun, wenn ich i->path().extension()
verwendet stattdessen von leaf()
. Was für mich funktionierte, war ein Beispiel aus this website. Hier ist der Code, geändert, einen Filter anwenden:
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);
}
}
}
I-Boost-Version bin mit: 1.53.0.
Warum wir nicht alle nur glob()
verwenden und einige Regex ist über mich hinaus.
- 1. Iterieren große Menge von Dateien in einem Verzeichnis
- 2. Iterieren durch eine boost :: dynamic_bitset
- 3. Wie kann ich VOLUME in einer Dockerfile verwenden, um einzelne Dateien in einem Verzeichnis persistent zu machen?
- 4. Iterieren durch jede Datei in einem Verzeichnis
- 5. Boost-Programmoptionen iterieren variables_map
- 6. Wie verwende ich R, um durch Unterordner zu Iterieren und CSV-Dateien derselben ID zu binden?
- 7. Kann ich TargetFileName verwenden, um eine Datei in einem Verzeichnis innerhalb einer Visual Studio-Vorlage hochzuladen?
- 8. Iterieren über ein Verzeichnis von Dateien mit GNU Make
- 9. Wie lösche ich alle Dateien in einem Verzeichnis mit Batch?
- 10. Kann eine Shell-Schleife alle Dateien in einem Verzeichnis entpacken?
- 11. Wie kann ich eine Regel in Gitignore schreiben, um alle Dateien außer Verzeichnisse in einem Verzeichnis zu ignorieren?
- 12. Iterieren über die Typen in einem Boost :: Variante
- 13. Unix Befehl, um alle Dateien in einem Verzeichnis zu löschen, aber das Verzeichnis zu behalten
- 14. Wie kann ich einen Glob verwenden, um Dateien zu ignorieren, die mit einem Unterstrich beginnen?
- 15. Verwenden von C#, um Formularfelder mit demselben Namen zu iterieren
- 16. Wie über Dateien mit Powershell zu iterieren?
- 17. Wie kann ich lame verwenden, um WAV-Dateien in einem Shell-Skript zu codieren?
- 18. Viele Dateien in einem Verzeichnis?
- 19. Wie kann ich wget verwenden, um Dateien mit scrapy
- 20. Wie verwende ich den Befehl 'mv', um Dateien außer denen in einem bestimmten Verzeichnis zu verschieben?
- 21. Wie boost :: preprocessor verwenden, um eine Sequenz zu entpacken?
- 22. Kann ich .htpasswd verwenden, um ein nicht vorhandenes Verzeichnis (ein virtuelles Verzeichnis mod_rewrite) zu sichern?
- 23. Boost mit Emscript verwenden
- 24. Wie lade ich alle Dateien aus einem Verzeichnis?
- 25. Count Dateien in einem Verzeichnis mit dem Dateinamen einen String
- 26. Iterieren durch ein Verzeichnis mit Ant
- 27. Kann ich ng-repeat verwenden, um in AngularJS über ein Array zu iterieren?
- 28. Wie kann ich Dateien mit Node.JS in ein Verzeichnis verschieben?
- 29. Wie kann ich eine Platzhaltersuche verwenden, um eine Liste von Scaffolding in einem CakePHP zu erhalten?
- 30. Verwenden von System.IO.Delete, um bestimmte Dateien aus einem Verzeichnis zu entfernen?
danke für die sehr vollständige antwort.zwei Anmerkungen für andere: 1) Leaf ist im Dateisystem v3 veraltet (aktueller Standard), benutze path(). filename() statt 2) Wenn das Filterkriterium die Erweiterung ist (sehr häufig), ist es einfacher, i-> path () .extension() == ".txt" [als Beispiel] als Regex – alfC
leaf() ist jetzt veraltet. i-> leaf() kann ersetzt werden durch i-> path(). string() oder i-> path(). filename(). string() wenn Sie nur die Dateinamen wollen – Fuzz
Der Backslash in Regex muss escaped sein '" Einige Dateien. * \\. txt "' –