gpt4 book ai didi

c++ - 无竞争目录遍历 (C++)

转载 作者:IT王子 更新时间:2023-10-29 00:39:32 26 4
gpt4 key购买 nike

我需要遍历目录树并获取每个文件的统计值。我想在修改文件系统时安全地执行此操作。

在 Python 中,最好的选择是 os.fwalk ,它可以访问正在遍历的目录的 fd;然后我可以使用 dir_fd (fstatat) os.stat 并获取当前统计值。这是在 Linux 上尽可能做到的无竞争(如果这个目录的内容被修改,我可能不得不重新扫描它)。在 C 中,有 nftw ,实现方式类似,fts ,它在 glibc 中使用普通的 (l)stat,因此很活泼(它通过更改目录来减少竞争窗口,这很不方便)。

C++ 有一个新的 filesystem API graduated from boost , 它缓存 stat 值但是 doesn't expose them (我需要访问 st_dev)。这不仅仅是一个头文件库,所以我无法解决这个问题。

我是否错过了一个不错的 C++ 选项,它使用 fstatat 并且不受 Boost 不公开平台特定调用的理想的约束?还是包装 nftw(甚至 find)是我最好的选择?

最佳答案

事实证明它很容易实现。

我用了libposix来自 dryproject。

#include <posix++.h>

class Walker {
public:
void walk(posix::directory dir) {
dir.for_each([this, dir](auto& dirent) {
if (dirent.name == "." or dirent.name == "..")
return;
if (!handle_dirent(dirent))
return;
struct stat stat;
if (dirent.type == DT_DIR || dirent.type == DT_UNKNOWN) {
int fd = openat(
dir.fd(), dirent.name.c_str(), O_DIRECTORY|O_NOFOLLOW|O_NOATIME);
if (fd < 0) {
// ELOOP when O_NOFOLLOW is used on a symlink
if (errno == ENOTDIR || errno == ELOOP)
goto enotdir;
if (errno == ENOENT)
goto enoent;
posix::throw_error(
"openat", "%d, \"%s\"", dir.fd(), dirent.name);
}
posix::directory dir1(fd);
fstat(fd, &stat);
if (handle_directory(dirent, fd, stat))
walk(dir1);
close(fd);
return;
}
enotdir:
try {
dir.stat(dirent.name.c_str(), stat, AT_SYMLINK_NOFOLLOW);
} catch (const posix::runtime_error &error) {
if (error.number() == ENOENT)
goto enoent;
throw;
}
handle_file(dirent, stat);
return;
enoent:
handle_missing(dirent);
});
}
protected:
/* return value: whether to stat */
virtual bool handle_dirent(const posix::directory::entry&) { return true; }
/* return value: whether to recurse
* stat will refer to a directory, dirent info may be obsolete */
virtual bool handle_directory(
const posix::directory::entry &dirent,
const int fd, const struct stat&) { return true; }
/* stat might refer to a directory in case of a race;
* it still won't be recursed into. dirent may be obsolete. */
virtual void handle_file(
const posix::directory::entry &dirent,
const struct stat&) {}
/* in case of a race */
virtual void handle_missing(
const posix::directory::entry &dirent) {}
};

性能与 GNU find 相同(与基类比较时,使用 -size $RANDOM 抑制输出并强制 findstat 所有文件,而不仅仅是 DT_DIR 候选文件)。

关于c++ - 无竞争目录遍历 (C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32821897/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com