Linux システム プログラミングでは、多くの場合、ディレクトリを走査して、ディレクトリ内のすべてのファイルとサブディレクトリを取得する必要があります。ディレクトリを再帰的に走査することは、C 言語を使用して実装できる一般的な方法です。このブログでは、C 言語を使用してディレクトリを再帰的に走査するプロセスを実装する方法を詳細に紹介し、対応するコード例を提供し、関連関数の使用法を説明します。
記事ディレクトリ
1. 関連機能の紹介
1.1 opendir()
1.1.1 関数プロトタイプ、パラメータ、戻り値
opendir
この関数は、ディレクトリを開いて、DIR
後続のディレクトリ操作に使用される型へのポインタを返すために使用されます。
プロトタイプ:
DIR *opendir(const char *path);
パラメータ:
path
: 開くディレクトリへのパス。
戻り値:
DIR
戻り値: ディレクトリが正常に開かれた場合は、その型へのポインタが返され、失敗した場合は、その型へのポインタが返されますNULL
。
1.1.2 機能例
opendir
以下は、関数を使用してディレクトリを開く例です。
#include <stdio.h>
#include <dirent.h>
int main() {
const char *path = "/path/to/directory";
DIR *dir = opendir(path);
if (dir == NULL) {
perror("opendir");
return -1;
}
// 目录操作...
closedir(dir);
return 0;
}
1.1.3 コードの説明
上の例では、最初にディレクトリ パスを open に定義しpath
、次にopendir
関数を使用してディレクトリを開き、返されたポインタをdir
変数に格納しました。readdir
次に、関数を使用してディレクトリ内のファイルを読み取るなど、いくつかのディレクトリ操作を実行できます。最後に、closedir
関数を使用してディレクトリを閉じます。
opendir
関数が失敗すると、NULL
エラー メッセージが返され、グローバル変数に保存されますerrno
。perror
デバッグやトラブルシューティングのためにエラー メッセージを出力する機能を使用できます。
DIR
この型のポインターを使用した後は、必ずclosedir
関数を使用してディレクトリを閉じ、関連リソースを解放する必要があることに注意してください。
1.2 readdir()
1.2.1 関数のプロトタイプ、パラメータ、戻り値、構造体定義
readdir
この関数は、ディレクトリ内のファイルを読み取り、dirent
構造体へのポインタを返すために使用されます。
プロトタイプ:
struct dirent *readdir(DIR *dir);
パラメータ:
dir
: 開いているディレクトリへのポインタ。
戻り値:
- 戻り値: 次のファイルの読み取りに成功した場合は、
dirent
構造体へのポインタが返され、ディレクトリの終端に到達した場合、またはエラーが発生した場合は、その構造体へのポインタが返されますNULL
。
dirent
構造は次のように定義されます。
struct dirent {
ino_t d_ino; // 文件的inode号
off_t d_off; // 文件在目录中的偏移量
unsigned short d_reclen; // 文件名的长度
unsigned char d_type; // 文件的类型
char d_name[256]; // 文件名
};
1.2.2 機能例
readdir
関数を使用してディレクトリ内のファイルを読み取る例を次に示します。
#include <stdio.h>
#include <dirent.h>
int main() {
const char *path = "/path/to/directory";
DIR *dir = opendir(path);
if (dir == NULL) {
perror("opendir");
return -1;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
printf("%s\n", entry->d_name);
}
closedir(dir);
return 0;
}
1.2.3 コードの説明
上記の例では、最初にopendir
関数を使用してディレクトリを開き、返されたポインタをdir
変数に格納します。次に、ループを使用してディレクトリ内の各ファイルを読み取ります。この関数は構造体へのポインターreaddir
を返します。メンバーにアクセスしてファイル名を取得し、対応する操作を実行できます。この例では、関数を使用してファイル名を出力するだけです。最後に、関数を使用してディレクトリを閉じます。dirent
d_name
printf
closedir
readdir
関数が を返した場合はNULL
、ディレクトリの末尾が読み取られたか、エラーが発生したことを意味することに注意してください。したがって、NULL
戻り値が であるかどうかで、ディレクトリ内のファイルの読み取りを続行するかどうかを判断できます。
1.3 クローズドIR()
1.3.1 関数プロトタイプ、パラメータ、戻り値
closedir
この関数は、以前に関数によって開かれたディレクトリを閉じopendir
、関連するリソースを解放するために使用されます。
プロトタイプ:
int closedir(DIR *dir);
パラメータ:
dir
: 開いているディレクトリへのポインタ。
戻り値:
- 戻り値: ディレクトリが正常に閉じられた場合は 0、エラーが発生した場合は -1。
1.3.2 関数の例
closedir
関数を使用してディレクトリを閉じる例を次に示します。
#include <stdio.h>
#include <dirent.h>
int main() {
const char *path = "/path/to/directory";
DIR *dir = opendir(path);
if (dir == NULL) {
perror("opendir");
return -1;
}
// 目录操作...
if (closedir(dir) == -1) {
perror("closedir");
return -1;
}
return 0;
}
1.3.3 コードの説明
上記の例では、最初にopendir
関数を使用してディレクトリを開き、返されたポインタをdir
変数に格納します。次に、ディレクトリ操作を行うことができます。最後に、closedir
関数を使用してディレクトリを閉じ、戻り値が -1 であるかどうかを確認して、エラーが発生したかどうかを確認します。
closedir
この関数はディレクトリに関連するリソースを解放するため、ディレクトリを使用した後は、忘れずに関数を呼び出してclosedir
ディレクトリを閉じる必要があることに注意してください。
1.4 snprintf()
1.4.1 関数プロトタイプ、パラメータ、戻り値
snprintf
function は、書式設定されたデータを文字列に出力するための安全な文字列書式設定関数です。
プロトタイプ:
int snprintf(char *str, size_t size, const char *format, ...);
パラメータ:
str
: フォーマットされた結果を格納するために使用される文字列へのポインタ。size
: フォーマットされた結果を格納する文字列のサイズ。format
: 形式文字列、出力形式を指定します。
戻り値:
- 戻り値: 成功した場合は文字列に書き込まれた文字数 (ターミネータは含まない) を返し、失敗した場合は負の値を返します。
snprintf
function はprintf
関数のように機能しますが、フォーマットされた結果を標準出力に出力するのではなく、指定された文字列に保存します。
1.4.2 関数例
snprintf
この関数を使用した例を次に示します。
#include <stdio.h>
int main() {
char buffer[100];
int num = 42;
const char *str = "Hello, world!";
int len = snprintf(buffer, sizeof(buffer), "Number: %d, String: %s", num, str);
if (len >= sizeof(buffer)) {
printf("Buffer is too small\n");
return -1;
}
printf("Formatted string: %s\n", buffer);
return 0;
}
1.4.3 コードの説明
buffer
上の例では、まず、フォーマットされた結果を格納するためにサイズ 100 の文字配列を定義します。次に、フォーマット文字列に渡される整数変数num
と文字列変数を定義します。str
次に、snprintf
関数を使用して、フォーマットされた結果を標準出力に保存しbuffer
、出力します。最後に、len
戻り値が のbuffer
サイズを超えているかどうかをチェックして、バッファーがフォーマットされた結果を保持するのに十分な大きさであるかどうかを確認します。
snprintf
この関数は、指定された書式文字列とパラメータに従って書式設定され、結果を指定された文字列に格納することに注意してください。これにより、フォーマットされた結果が指定されたサイズを超えないことが保証され、必要に応じて文字列が自動的に切り詰められます。したがって、snprintf
関数を使用すると、バッファ オーバーフローの問題を回避できます。
1.5 strcmp()
1.5.1 関数プロトタイプ、パラメータ、戻り値
strcmp
2 つの文字列が等しいかどうかを比較する関数。
プロトタイプ:
int strcmp(const char *s1, const char *s2);
パラメータ:
s1
: 比較する最初の文字列。s2
: 比較する 2 番目の文字列。
戻り値:
- 戻り値: 2 つの文字列が等しい場合は 0 を返し、最初の文字列が 2 番目の文字列より小さい場合は負の数値を返し、最初の文字列が 2 番目の文字列より大きい場合は正の数値を返します。
strcmp
この関数は、等しくない文字が見つかるか文字列の終わりに達するまで、2 つの文字列を辞書順に 1 文字ずつ比較します\0
。2 つの文字列が等しい場合は 0 を返します。最初の文字列が辞書順で 2 番目の文字列より前にある場合は負の数を返します。最初の文字列が辞書順で 2 番目にある場合は負の数を返します。文字列の後には、正の数が返されます。
1.5.2 関数の例
strcmp
関数を使用して 2 つの文字列を比較する例を次に示します。
#include <stdio.h>
#include <string.h>
int main() {
const char *s1 = "Hello";
const char *s2 = "World";
int result = strcmp(s1, s2);
if (result == 0) {
printf("The strings are equal\n");
} else if (result < 0) {
printf("The first string is less than the second string\n");
} else {
printf("The first string is greater than the second string\n");
}
return 0;
}
1.5.3 コードの説明
上の例では、2 つの文字列を定義しs1
、関数をs2
使用してそれらを比較しました。strcmp
戻り値に応じて、対応する結果を出力します。
strcmp
この関数は文字列のアドレスではなく、文字列の内容を比較することに注意してください。したがって、2 つの文字列のアドレスが異なっていても、その内容が同じであれば、strcmp
関数は 0 を返します。また、strcmp
関数では大文字と小文字が区別されます。大文字と小文字を区別せずに比較したい場合は、関数を使用できますstrcasecmp
。
2. 再帰的トラバーサルディレクトリの実装
2.1 サンプルコード:
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
void traverse_directory(const char *path) {
DIR *dir;
struct dirent *entry;
struct stat file_stat;
// 打开目录
dir = opendir(path);
if (dir == NULL) {
perror("opendir");
return;
}
// 读取目录中的每个文件
while ((entry = readdir(dir)) != NULL) {
// 构建文件的完整路径
char file_path[1024];
snprintf(file_path, sizeof(file_path), "%s/%s", path, entry->d_name);
// 获取文件的信息
if (lstat(file_path, &file_stat) < 0) {
perror("lstat");
continue;
}
// 判断文件类型
if (S_ISDIR(file_stat.st_mode)) {
// 如果是目录,则递归遍历
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
traverse_directory(file_path);
} else {
// 如果是文件,则打印文件名
printf("%s\n", file_path);
}
}
// 关闭目录
closedir(dir);
}
int main(int argc,char *argv[]) {
traverse_directory(argv[]);
return 0;
}
2.2 コードの説明
上記のコードでは、traverse_directory
ディレクトリを再帰的に走査する関数を定義しました。この関数は引数としてパスを受け取り、最初にディレクトリを開き、次にディレクトリ内の各ファイルを読み取ります。ファイルごとに、最初にファイルへの絶対パスを構築し、次にlstat
関数を使用してファイルの情報を取得します。ファイルがディレクトリの場合、関数は再帰的に呼び出されtraverse_directory
、ファイルが通常のファイルの場合、ファイル名が出力されます。最後に、ディレクトリを閉じます。
関数ではmain
、走査するディレクトリ パスを指定し、traverse_directory
走査する関数を呼び出します。
dirent.h
上記のコードでは、ヘッダーファイルはディレクトリとファイルの操作に使用されsys/stat.h
、stdio.h
ヘッダーstring.h
ファイルは文字列操作の実行に使用されることに注意してください。lstat
また、関数はシンボリック リンクを処理できるため、ファイルに関する情報を取得するには、stat
関数ではなく関数がコード内で使用されますlstat
。