LoginSignup
1
0

More than 5 years have passed since last update.

fts でファイル階層をたどる

Posted at

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/
1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0