スポンサーリンク

このドキュメントの内容は、以下の通りです。

はじめに


プログラムを開発しているときに、ファイルを読み書きすることがあります。ファイルを読み書きするときに、ディレクトリ内のファイルを探すこともあるでしょう。Unix系OS(FreeBSDやLinuxなど)は、C言語でディレクトリ情報(ディレクトリエントリ) を取得するには、opendir()/readdir()/closedir()を使えば取得することができます。他の言語でも類似の関数が提供されていることもあると思います。

より簡単にディレクトリエントリのリストを取得する方法があります。 それは、scandir()関数を利用することです。

scandir とは


scandir()関数は、指定されたディレクトリを走査し、 ディレクトリのエントリのリストを作成します。エントリの情報は、malloc()によってメモリを確保されるため、 不要になったときにfree()関数でメモリを開放する必要があります。つまり、scandirを利用する場合には、注意が必要です。

scandir の定義


以下は、 FreeBSD の scandirの定義は、以下のヘッダファイルにあります。
#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 *));


サンプルコード


カレントディレクトリのディレクトリエントリのリストを取得し、表示するサンプルプログラムです。

戻り値の意味は、以下の通りです。
  • scandirは成功した場合、取得したエントリの数を返します。
  • scandirは失敗した場合は、-1を返します。
失敗するときは、ディレクトリが存在しないか、メモリが足りず、malloc()が失敗したのが原因でしょう。

scandir.c
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <sys/types.h>
#include <dirent.h>

int
main (int argc, char *argv[])
{
	int	i;

	const char *dirname = ".";
	struct dirent **namelist;
	int r = scandir(dirname, &namelist, NULL, NULL);
	if(r == -1) {
		err(EXIT_FAILURE, "%s", dirname);
	}
	(void) printf ("%d\n", r);
	for (i = 0; i < r; ++i) {
		(void) printf ("%s\n", namelist[i]->d_name);
		free(namelist[i]);
	}
	free(namelist);

	exit (EXIT_SUCCESS);
}

コンパイル方法


コンパイル方法は、以下の通りです。
cc scandir.c

実行結果

以下は実行結果です。
% ./a.out
4
.
..
scandir.c
a.out

上記の例(scandir.c)では、第4引数の比較関数を指定していないため、取得したリストがソート(sort)されていません。アルファベット順にソートするには、そのための比較関数をscandirに渡してやる必要があります。strcmp()で比較した結果でソートすれば、アルファベット順にソートすることが可能です。

ソートをするサンプルコード


scandir 関数は、第4引数の比較関数を指定することで、ファイル名のリストをソートできます。アルファベット順にソートするには、そのための比較関数をscandirに渡してやる必要があります。strcmp()で比較した結果でソートすれば、アルファベット順にソートすることが可能です。

scandir_compare.c

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>

int
compar(const struct dirent **s1, const struct dirent **s2)
{
	return strcmp( (*s1)->d_name, (*s2)->d_name);
}

int
main (int argc, char *argv[])
{
	int	i;

	const char *dirname = ".";
	struct dirent **namelist;
	int r = scandir(dirname, &namelist, NULL, compar);
	if(r == -1) {
		err(EXIT_FAILURE, "%s", dirname);
	}
	(void) printf ("%d\n", r);
	for (i = 0; i < r; ++i) {
		(void) printf("%s\n", namelist[i]->d_name);
		free(namelist[i]);
	}
	free(namelist);

	exit (EXIT_SUCCESS);
}

また、アルファベット順にソートする場合は、自分でオリジナルの ソート関数を作らなくても、alphasort()関数をscandir()に渡してやれば、簡単にできます。

scandir_alphasort.c

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>

int
main (int argc, char *argv[])
{
	int	i;

	const char *dirname = ".";
	struct dirent **namelist;
	int r = scandir(dirname, &namelist, NULL, alphasort);
	if(r == -1) {
		err(EXIT_FAILURE, "%s", dirname);
	}
	(void) printf ("%d\n", r);
	for (i = 0; i < r; ++i) {
		(void) printf("%s\n", namelist[i]->d_name);
		free(namelist[i]);
	}
	free(namelist);

	exit (EXIT_SUCCESS);
}

ディレクトリエントリを含める含めないの判定をするサンプルコード


ファイルをスキャンしていくときに、そのファイルを含める、含めないといった判定をすることもできます。たとえば、ファイル名のマッチングをしたり、拡張子でマッチングをする、といったことが必要なこともあるでしょう。


scandir()の第3引数には、ディレクトリエントリをリストに含めるかどうかを決めるための関数を指定することができます。たとえば、 '.'(ドット)で始まる名前は、リストに含めない例を示します。

scandir_select.c
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>

int
selects(struct dirent *dir)
{
	if(dir->d_name[0] == '.')
	{
		return (0);
	}
	return (1);
}

int
main (int argc, char *argv[])
{
	int	i;

	const char *dirname = ".";
	struct dirent **namelist;
	int r = scandir(dirname, &namelist, selects, alphasort);
	if(r == -1) {
		err(EXIT_FAILURE, "%s", dirname);
	}
	(void) printf ("%d\n", r);
	for (i = 0; i < r; ++i) {
		(void) printf("%s\n", namelist[i]->d_name);
		free(namelist[i]);
	}
	free(namelist);

	exit (EXIT_SUCCESS);
}

実行結果

.や..が含まれなくなりました。
2
a.out
scandir.c

スポンサーリンク
スポンサーリンク
 
いつもシェア、ありがとうございます!


もっと情報を探しませんか?

関連記事

最近の記事

人気のページ

スポンサーリンク
 

過去ログ

2020 : 01 02 03 04 05 06 07 08 09 10 11 12
2019 : 01 02 03 04 05 06 07 08 09 10 11 12
2018 : 01 02 03 04 05 06 07 08 09 10 11 12
2017 : 01 02 03 04 05 06 07 08 09 10 11 12
2016 : 01 02 03 04 05 06 07 08 09 10 11 12
2015 : 01 02 03 04 05 06 07 08 09 10 11 12
2014 : 01 02 03 04 05 06 07 08 09 10 11 12
2013 : 01 02 03 04 05 06 07 08 09 10 11 12
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
2003 : 01 02 03 04 05 06 07 08 09 10 11 12

サイト

Vim入門

C言語入門

C++入門

JavaScript/Node.js入門

Python入門

FreeBSD入門

Ubuntu入門

セキュリティ入門

パソコン自作入門

ブログ

トップ


プライバシーポリシー