ディレクトリの読み方

その手の作業はperlでしていたのでCでディレクトリを読む方法を調べてみた。なんと標準Cではディレクトリを読むそうさって無いのね。まぁファイルシステムが無いような環境もあるからな。とりあえずgccで探してみる。opendir, readdir, closedirなんかで読むのね。DIRとかstruct direntがどうなってるか謎だったのでヘッダファイルを見てみたけど結局DIR*とd_nameぐらいを使っていれば良さそうだ。ディレクトリ名を持ち回るのでバッファオーバーフローしないようにバッファの管理が面倒だ。ディレクトリを引数で渡して再帰的にファイル名(ディレクトリ名も)をリストアップするコードを書いてみた。.で始まるファイル名は省くようにした。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <dirent.h>

#define PATHSIZE (1024)

/* ディレクトリをシークしてファイル名を書き出す */
/* ディレクトリが入れ子になっている場合は再帰的に実行する */
void seekDir(char const *dirName)
{
    DIR *dp;  /* ディレクトリポインタ */
    struct dirent *pDEntry;
    char fullPathName[PATHSIZE];
    
    dp = opendir(dirName);
    if (dp == NULL) {
        /* 開けなかったらそのまま戻る */
        /* ファイルなら開けないはず */
        return;
    }
    
    while ((pDEntry = readdir(dp)) != NULL) {
        /* 名前の先頭がカンマの場合はスキップ */
        if (pDEntry->d_name[0] == '.') {
            continue;
        }

        if ((strlen(dirName) + strlen(pDEntry->d_name) + 2) >= PATHSIZE ) {
            /* パス名がバッファあふれたらあぼーん */
            fprintf(stderr, "パス名が長すぎます\n");
            exit(-1);
        }
        
        /* ファイル名にパスを付加する */
        sprintf(fullPathName, "%s/%s", dirName, pDEntry->d_name);
        /* ファイル名を表示 */
        printf("%s\n", fullPathName);

        /* 再帰的に実行する。 */
        /* ファイルなら失敗してそのまま戻ってくる */
        seekDir(fullPathName);
    }
    closedir(dp);
}

int main(int argc, char **argv)
{
    /* 引数チェック */
    if (argc != 2) {
        fprintf(stderr, "usage: listUp DIRECTORY_NAME\n");
        return -1;
    }
    seekDir(argv[1]);
    
	return 0;
}