Вам нужен рекурсивный алгоритм дерева, который отслеживает, какие каталоги уже были посещены.
Вы должны либо канонировать пути для этой цели, либо использовать комбинацию (device,inode)
для проверки состояния посещения. Это делается для того, чтобы исключить циклические циклы ссылок или разные варианты написания с тем же именем.
В моем простом примере:
for (fs::path current : { ".", "..", "../..", "../../../" }) {
auto const& sub = recurse(fs::canonical(current));
if (!sub.empty())
return sub;
}
Он также учитывает для случая, когда, например, ../..
и ../../../
ссылаются на этот же справочник (/
).
Демо-выход:
mkdir -p haystack/{a..z}/sub/{1..10} haystack/j/sub/9/needle
g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp -lboost_system -lboost_filesystem -o test
cd haystack/k/sub/4 && ../../../../test
FOUND "/tmp/1429002953.62583/haystack/j/sub/9/needle"
Live On Coliru или Live On Coliru (c++03)
#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>
#include <functional>
#include <set>
#include <iostream>
namespace fs = boost::filesystem;
fs::path find_directory(std::string const& name) {
std::set<fs::path> visited;
std::function<fs::path(fs::path const&)> recurse;
recurse = [&visited, &name, &recurse](fs::path const& dir) -> fs::path {
if (visited.insert(dir).second) { // not visited already
try {
for (auto& de : boost::make_iterator_range(fs::directory_iterator(dir), {})) {
if (fs::is_directory(de))
{
if (de.path().filename() == name)
return de.path();
// TODO check accessibility?
auto const& sub = recurse(de.path());
if (!sub.empty())
return sub;
}
}
} catch(fs::filesystem_error& e) {
std::cerr << "Error: " << e.what() << "\n";
}
}
return {};
};
for (fs::path current : { ".", "..", "../..", "../../../" }) {
auto const& sub = recurse(fs::canonical(current));
if (!sub.empty())
return sub;
}
return {};
}
int main() {
std::cout << "FOUND " << find_directory("needle") << "\n";
}
'oItrEnd' ошибочно после установки' oItr', чтобы указать на подкаталог. Но даже если вы обновили 'oEndItr', когда вы идете глубже, ваш код должен отслеживать весь * стек *' OEndItr', чтобы завершить цикл каждого вложенного каталога. Таким образом, вы можете создать стек или даже проще, рекурсивную функцию, которая использует «стек», поэтому вам не нужно создавать свои собственные. – VoidStar