A note on how to navigate the file hierarchy using fts.
Create a sample program that scans the directory given by the argument and outputs the size and pathname.
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;
}
The directory and file size paths can be output recursively.
$ 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
By giving a function pointer to fts_open, it seems possible to change the order in which the file hierarchy is scanned.
$ 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.
...
So, modify it to give a function pointer so that the size is output in ascending order, and execute it again.
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;
}
Files in the directory are now output in ascending order of size.
$ 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/
Recommended Posts