C言語 scandir()でディレクトリエントリのリストを取得する方法
スポンサーリンク
このドキュメントの内容は、以下の通りです。
はじめに
プログラムを開発しているときに、ファイルを読み書きすることがあります。ファイルを読み書きするときに、ディレクトリ内のファイルを探すこともあるでしょう。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を返します。
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
スポンサーリンク
スポンサーリンク
いつもシェア、ありがとうございます!
もっと情報を探しませんか?
関連記事
最近の記事
- パナソニック ジェットウォッシャードルツ EW-DJ61-Wのホースの修理
- LinuxセキュリティモジュールIntegrity Policy Enforcement
- アマゾンのEcho Show 5を買ったのでレビューします
- アマゾンのサイバーマンデーはAlexa Echo Show 5が安い
- Android スマートフォン OnePlus 7T と OnePlus 7の違い
- Android スマートフォン OnePlus 7 をAndroid10にアップデートしてみた
- クレジットカードのバーチャルカードの比較のまとめ
- 活動量計 Xiaomi Mi Band 4を買ってみたのでレビュー
- Android スマートフォン OnePlus 7 のレビュー
- AliExpressでスマートフォンを買い物してみた
- パソコンのホコリ対策 レンジフードフィルターと養生テープ
- 80PLUS GOLDのPC電源ユニットAntec NeoEco 750 Goldのレビュー
- イギリスの付加価値税 VAT は払い戻しを受けられる
- イギリスのロンドンでスーツケースなど荷物を預けられる場所は
- イギリスのロンドンで地下鉄やバスに乗るならオイスターカードを使おう
- イギリスのヒースロー空港からロンドン市内への行き方
- 航空便でほかの航空会社に乗り継ぎがある場合のオンラインチェックイン
- SFC会員がANA便ではなくベトナム航空のコードシェアを試して解ったこと
- ベトナムの入国審査でeチケットの掲示が必要だった話
- シアトルの交通ICカードはオルカカード(Orca)です
人気のページ
- Windows7 IME 辞書ツールで単語の登録に失敗しました
- C言語 popen()でコマンドを実行して出力を読み込む
- Windows7で休止状態にする方法
- CentOS MySQLの起動、停止、再起動
- loggerコマンドでsyslogにエラーを出力する方法
- パソコンパーツの買取をしてくれる店のまとめ
- Java Mapの使い方 get(),put(),remove(),size(),clear()
- 楽天のRポイントカードを作ってみた
- iPhone 5 から iPhone 6 に乗り換えたのでレビュー
- netstatコマンドのステータスの意味
スポンサーリンク
過去ログ
2020 : 01 02 03 04 05 06 07 08 09 10 11 122019 : 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