fts を使用したファイル階層のたどり方のメモ。
サンプル
引数で与えられたディレクトリを走査し、サイズとパス名を出力するサンプルプログラムを作成します。
sample.cpp
# include <cstdio>
# include <fts.h>
# include <sys/stat.h>
int main(int argc, char** argv)
{
if (argc != 2) {
std::fprintf(stderr, "Usage: %s <dir>\n", argv[0]);
return -1;
}
char* const paths[] = {argv[1], nullptr};
FTS* fts = fts_open(paths, 0, nullptr);
if (fts == nullptr) {
std::fprintf(stderr, "open failed.\n");
return -1;
}
FTSENT* ent = nullptr;
while ((ent = fts_read(fts)) != nullptr) {
std::printf("%-5lu %s\n", ent->fts_statp->st_size, ent->fts_path);
}
if (fts_close(fts) != 0) {
std::fprintf(stderr, "close failed.\n");
return -1;
}
return 0;
}
再帰的にディレクトリとファイルのサイズ・パスが出力できています。
$ g++ -std=c++14 sample.cpp -o sample
$ ./sample testdir
4096 testdir
4096 testdir/subdir
114 testdir/subdir/fff.txt
110 testdir/subdir/eee.txt
49 testdir/subdir/ddd.txt
4096 testdir/subdir
64 testdir/bbb.txt
48 testdir/aaa.txt
8 testdir/ccc.txt
4096 testdir
ファイル階層走査順の変更
fts_open に関数ポインタを与えることで、ファイル階層を走査する順序の変更が可能なようです。
$ man fts
...
FTS *fts_open(char * const *path_argv, int options,
int (*compar)(const FTSENT **, const FTSENT **));
...
The argument compar() specifies a user-defined function which may be used to order the traversal of the hierarchy.
It takes two pointers to pointers to FTSENT structures as arguments and should return a negative value, zero, or a positive value to indicate if the file referenced by its first argument comes before, in any order with respect to, or after, the file referenced by its second argument.
...
ということで、サイズが昇順で出力されるように関数ポインタを与えるよう修正し、再度実行します。
sample2.cpp
# include <cstdio>
# include <fts.h>
# include <sys/stat.h>
static int compar(const FTSENT** rhs, const FTSENT** lhs)
{
const FTSENT* r = *rhs;
const FTSENT* l = *lhs;
return (r->fts_statp->st_size - l->fts_statp->st_size);
}
int main(int argc, char** argv)
{
if (argc != 2) {
std::fprintf(stderr, "Usage: %s <dir>\n", argv[0]);
return -1;
}
char* const paths[] = {argv[1], nullptr};
FTS* fts = fts_open(paths, 0, compar);
if (fts == nullptr) {
std::fprintf(stderr, "open failed.\n");
return -1;
}
FTSENT* ent = nullptr;
while ((ent = fts_read(fts)) != nullptr) {
std::printf("%-5lu %s\n", ent->fts_statp->st_size, ent->fts_path);
}
if (fts_close(fts) != 0) {
std::fprintf(stderr, "close failed.\n");
return -1;
}
return 0;
}
ディレクトリ内のファイルが、サイズの小さい順に出力されるようになりました。
$ g++ -std=c++14 sample2.cpp -o sample2
$ ./sample2 testdir/
4096 testdir/
8 testdir/ccc.txt
48 testdir/aaa.txt
64 testdir/bbb.txt
4096 testdir/subdir
49 testdir/subdir/ddd.txt
110 testdir/subdir/eee.txt
114 testdir/subdir/fff.txt
4096 testdir/subdir
4096 testdir/