1. 概要
このあたりになると、プラットフォームや個々のコンパイラにより、ヘッダファイル名や動作にばらつきが見られてきます。
2. dirname, basename ディレクトリ名
#include <libgen.h>
char *dirname(char *path);
char *basename(char *path);
「dirname」は、「path」で示す、フルパスのファイル名より、ディレクトリの部分文字列を取得します。
「basename」は、「path」で示す、フルパスのファイル名より、ファイル名のみの部分文字列を取得します。
3. flock ファイル排他
#include <sys/file.h>
#define LOCK_SH 0x01 /* 共有ファイルロック */
#define LOCK_EX 0x02 /* 排他的ファイルロック */
#define LOCK_NB 0x04 /* ロックするときにブロックしない */
#define LOCK_UN 0x08 /* ファイルをアンロックする */
int flock(int fd, int operation);
「flock」は、ファイル記述子「fd」(「open」の戻り値のファイルディスクリプタです)に対応するファイル上の 問合せ型ロックを適用または除去します。
ロックを適用するには、「operation」引数に「LOCK_SH」または「LOCK_EX」のいずれかと、必要であれば「LOCK_NB」を加えて指定します。
既存のロックをアンロックする場合は「operation」を「LOCK_UN」にします。
これ、使い方は、下記のサイトが参考になります。
「ファイルに対してロックの適用・解除を行う – C言語入門講座」
いささか、長いですが、下記のソースを書いて・・・。
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/file.h>
int main(int argc, char *argv[])
{
char afilename[PATH_MAX] = "./lock"; // ロックファイル
int nfd = -1;
printf("ロックします。\n");
while(true)
{
if (nfd == -1)
{
nfd = open(afilename, O_WRONLY | O_CREAT);
if (nfd == -1)
{
continue;
}
}
if (flock(nfd, LOCK_EX) == 0)
{
break;
}
usleep(1000);
}
printf("ロックしました。\n");
printf("[Enter] を入力してください。 ");
getchar();
printf("解除します。\n");
flock(nfd, LOCK_UN);
close(nfd);
remove(afilename);
printf("解除しました。\n");
return 0;
}
2つの端末で同じディレクトリで、上記のファイルから作成したロードモジュールを起動すると
先に起動した方が
ロックします。
ロックしました。
[Enter] を入力してください。
の状態で止まり、後で起動した方が
ロックします。
の状態で止まります。
先に起動した方に Enter を入力すると
解除します。
解除しました。
で終了し、後で起動した方が
ロックしました。
[Enter] を入力してください。
で止まって、ロックした状態になります。
4. scandir, alphasort ディレクトリ検索
#include <sys/types.h>
#include <dirent.h>
int scandir(const char *dirname, struct dirent ***namelist,
int (*select)(struct dirent *), int (*compar)(const void *, const void *));
int alphasort(const void *d1, const void *d2);
「scandir()」関数はディレクトリ「dirname」を読み取り、「malloc」を使用して、ディレクトリエントリを指すポインタの配列を作成します。
そして配列内のエントリの数を返します。
ディレクトリエントリの配列を指すポインタは、 「namelist」が参照する位置に保存されます。
「select」パラメータは、どのエントリを配列に入れるかを選択するために「scandir()」 によって呼び出される、ユーザ定義サブルーチンを指すポインタです。
選択ルーチンにはディレクトリエントリを指すポインタが渡されます。
また、ディレクトリエントリを配列に入れる場合は非 0 の値を返さなくてはなりません。
「select」が「NULL」の場合、すべてのディレクトリエントリが組み入れられます。
「compar」パラメータは、ユーザ定義サブルーチンを指すポインタであり、このサブルーチンは完成した配列をソートするために 「qsort」に渡されます。
このポインタが「NULL」の場合、配列はソートされません。
「alphasort()」関数は、「compar」パラメータに使用できるルーチンで、配列をアルファベット順にソートします。
配列用に割当てられたメモリを「free」で割当て解除できます。
その場合、配列内の各ポインタを解放してから、配列自体を解放してください。
わたしがよく使う使い方は
no = scandir(ディレクトリ文字列, &namelist, 0, alphasort);
for (i=0; i<no; i++)
{
// namelist[i] にファイル名が 入っているので
// ファイルに対して何らかの処理を行います
free(namelist[i]);
}
free(namelist);
ループ内で、「namelist」の各配列を解放して、ループ外で、「namelist」自体を解放します。
この場合、ループ内部で、「continue」等により、配列内の開放を忘れないこと、戻り値が「-1」のときは、「namelist」自体にメモリが割り当てられていないので、解放してはいけないことを注意しなければなりません。