您需要一个树递归算法来跟踪已访问过的目录。
您应该为此目的规范化路径或使用(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";
}