ファイル操作もオンラインプログラムの重要な作業の一つです。ファイルの 存在やアクセス権を調べたり、所有者、グループなどの属性の設定、変更日付 の操作など入出力操作以外にやらなければならないことがたくさんあります。 例えばデータファイルを作るのに同じ名前のファイルが存在するかどうか調べ、 それが空でなければ.bakにリネームして新たにファイルを作るとか、ファイル システムの空き容量を調べファイルに書き出せるデータ量を決定するとかです。 それらのために次のようなシステムコールが用意されています。
int access( char *path, int mode ) ファイルのアクセスモードの検査 int stat( char *path, struct stat *buf ) ファイルステータスを得る。 int ustat( dev_t dev, struct ustat *buf) ファイルシステム統計の情報を得る。 int chown( char *path, int own, int grp ) ファイルのオーナ/グループの変更 int chmod( char *path, mode_t mode ) ファイルのモード変更 int umask( int mask ) ファイル作成モードマスクの設定/取得 int chdir( char *path ) ワーキングディレクトリの変更 int mkdir( char *path, int mode ) ディレクトリ作成 int rmdir( char *path ) ディレクトリ削除 int unlink( char *path ) ファイルの削除 int rename( char *path1, char *path2 ) ファイル名の変更 int symlink( char *name1, char *name2 ) シンボリックリンク作成 int readlink( char path, char *buf, int siz ) シンボリックリンクの値読み取り int utimes( char *file, struct timeval *tvp ) ファイルアクセス/変更時間設定 int fcntl( int fd, int cmd, int arg ) ファイル記述子/フラグ/ロックの制御
これらのうちの多くのものは同じ名前のシェルコマンドとして用意されてい ますから特に必要はないと思います。詳しくはmanを見てください。fcntlにつ いてはプロセス間通信で見ます。statについてここでは上述の例(ファイル名 に.bakを付けて保存)に従ってやってみましょう。
statは/usr/include/sys/stat.hに定義されている次のような構造体にファ イルの情報を返します。
struct stat { dev_t st_dev; //ファイルが存在するデバイスのID ino_t st_ino; //Iノード番号 mode_t st_mode; //ファイルモード short st_nlink; //リンクカウント uid_t st_uid; //オーナのユーザID gid_t st_gid; //オーナのグループID dev_t st_rdev; //デバイススペシャルファイル off_t st_size; //ファイルサイズ(バイト) time_t st_atime; //最終アクセス時間 int st_spare1; time_t st_mtime; //最終更新時間 int st_spare2; time_t st_ctime; //最終変更時間(属性変更含む) int st_spare3; long st_blksize; //ブロックサイズ long st_blocks; //ブロック数 long st_spare4[2]; };
いまから/data1/run0001.datというファイルを出力用に用意したいと思います。 statでファイルの情報を得ましょう。
#include <sys/type.h> #include <sys/stat.h> struct stat statbuf; int st; st = stat( "/data1/run0001.dat", &statbuf ); if( st == -1 ) { /*この場合はエラー。ファイルがないのかもしれない。*/ } /*errnoグローバル変数にエラーコードが書かれている。*/ else { /*ファイルが存在する。サイズを調べて0でなければ */ } /*renameしてバックアップする。*/
errnoがENOENTの場合はファイルが存在しません。この場合はあらたにopenす ればよいことになります。存在するが長さが0の時、すなわちstatbuf.st_size が0の時そのままopenしましょう。長さが0でないときは.bakを付けた名前に renameします。そしてあらたにopenします。
次に/data1というファイルシステムには後どれだけデータが書けるか調べま しょう。ファイルシステムの情報はustatで得られます。
#include <sys/types.h> #include <ustat.h> struct ustat ustatbuf; st = ustat( statbuf.st_dev, & ustatbuf );
先程のstatシステムコールで/data1/run0001.datのあるファイルシステムのID がst_devにあります。それを使って呼び出します。ustatはustat構造体に次の ような情報を返します。
struct ustat { daddr_t f_tfree; /* 総空きブロック数 */ ino_t f_tinode; /* 空きIノード数 */ char f_fname[6]; /* ファイルシステム名 */ char f_fpack[6]; /* パックされたファイルシステム名 */ };
ustatbuf.f_tfreeに空きバイト数が書かれています。これを見ればあとどれだ けデータが書けるかわかることになります。
場合によってはあるディレクトリの中にあるファイルを一つづつ調べていき たい場合があります。システムコールではありませんが、そのためのCライブ ラリ関数のセットがあります。
opendir あるディレクトリをサーチのために開く。 readdir 開かれているディレクトリの中のファイルを一つ読む。 closedir ディレクトリを閉じる。 rewinddir ディレクトリサーチを巻き戻す。 telldir ディレクトリの中の現在位置を返す。 seekdir ディレクトリの指定位置に移動する。
readdirが返してくれるのはdirent構造体へのポインターです。dirent.hに定 義されています。ファイル名は構造体メンバーd_name、ファイル名の長さは d_namlenで与えられます。そのファイル名をstatすればディレクトリも見つけ ることができます。chdirしてさらにo pendirすればディレクトリツリーのな かをどこまでもたどることができます。