ファイルの情報取得

このエントリーをはてなブックマークに追加

前回はディレクトリに含まれるファイルの一覧を取得する方法について解説しました。
今回は、ここで取得したファイルからファイルの情報を取得する方法を解説します。

ファイルの種類の判定

ファイルの一覧を取得は可能になりましたが、このままではディレクトリかファイルかの判定が出来ておらず不便ですね。
ファイルの種類や状態を取得するにはstat(2)、lstat(2)、fstat(2)を使用します。
statとlstatはほぼ同じで、ファイルのパス名から対象のパスの状態等を取得します。違いはシンボリックリンクの場合の動作です。
また、statとfstatとの違いはstat/lstatはパスを渡すのに対して、fstatにはファイルディスクリプタを渡す点が異なります。

ではstatの使い方を見てみます。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(void) {
        int ret;
        struct stat buf;

        ret = stat("/bin/bash", &buf);
        if (ret < 0) {
                       return 1;
        }

        printf("%d\n", S_ISREG(buf.st_mode));
        printf("%d\n", S_ISDIR(buf.st_mode));

        return 0;
       }


まずは動作から見てみましょう。
$ ./stat
1
0

解説

stat関数には対象のパス名とstruct statの変数(今回はbuf)を渡します。
stat関数が正常終了するとbufに値を設定します。bufの値を見ることにより、ファイルの種類や更新日等が分かります。

struct statの宣言は以下の通りです。

truct stat {
	dev_t     st_dev;     /* ファイルがあるデバイスの ID */
	ino_t     st_ino;     /* inode 番号 */
	mode_t    st_mode;    /* アクセス保護 */
	nlink_t   st_nlink;   /* ハードリンクの数 */
	uid_t     st_uid;     /* 所有者のユーザ ID */
	gid_t     st_gid;     /* 所有者のグループ ID */
	dev_t     st_rdev;    /* デバイス ID (特殊ファイルの場合) */
	off_t     st_size;    /* 全体のサイズ (バイト単位) */
	blksize_t st_blksize; /* ファイルシステム I/O でのブロックサイズ */
	blkcnt_t  st_blocks;  /* 割り当てられた 512B のブロック数 */
	time_t    st_atime;   /* 最終アクセス時刻 */
	time_t    st_mtime;   /* 最終修正時刻 */
	time_t    st_ctime;   /* 最終状態変更時刻 */
};

今回の目的であるファイルの種類はst_modeから取得します。ただし、直接st_modeを参照するのではなくマクロを使用します。
使用可能なマクロは以下の通りです。
マクロ説明
S_ISREG(m)通常のファイルか?
S_ISDIR(m)ディレクトリか?
S_ISCHR(m)キャラクターデバイスか?
S_ISBLK(m)ブロックデバイスか?
S_ISFIFO(m)FIFO (名前付きパイプ) か?
S_ISLNK(m)シンボリックリンクか? (POSIX.1-1996 にはない)
S_ISSOCK(m)ソケットか? (POSIX.1-1996 にはない)


通常結果を判定するのは簡単です。
if (S_ISREG(buf.st_mode)) {
	//通常のファイルの場合
}

struct statを見ればファイルのユーザID、グループIDもありますしファイルサイズ等も取得できそうです。
ここまでくればlsコマンドを自分で作成出来るのではないでしょうか?


まとめ

ファイルはUnixの基本であり、この情報を扱うことがUnixプログラミングでは非常に大切なこととなります。
lsコマンドはUnixでは非常によく使うコマンドですが意外と作れそうですね。是非一度挑戦してはいかがでしょうか?