C言語 - 標準ライブラリ - その他

クラウディア 
1. 概要
2. dirname, basename ディレクトリ名
3. flock ファイル排他
4. scandir, alphasort ディレクトリ検索

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」自体にメモリが割り当てられていないので、解放してはいけないことを注意しなければなりません。
earthcar(アースカー)
葬送のフリーレン Prime Video