【Linuxオペレーティングシステム】ディレクトリの再帰的トラバースを実現するLinuxシステムプログラミング、opendir、readdir、closedir、snprintf、strcmpなどの関数の使い方を詳しく解説

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エラー メッセージが返され、グローバル変数に保存されますerrnoperrorデバッグやトラブルシューティングのためにエラー メッセージを出力する機能を使用できます。

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を返します。メンバーにアクセスしてファイル名を取得し、対応する操作を実行できます。この例では、関数を使用してファイル名を出力するだけです。最後に、関数を使用してディレクトリを閉じます。direntd_nameprintfclosedir

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 関数プロトタイプ、パラメータ、戻り値

snprintffunction は、書式設定されたデータを文字列に出力するための安全な文字列書式設定関数です。


プロトタイプ:

int snprintf(char *str, size_t size, const char *format, ...);

パラメータ:

  • str: フォーマットされた結果を格納するために使用される文字列へのポインタ。
  • size: フォーマットされた結果を格納する文字列のサイズ。
  • format: 形式文字列、出力形式を指定します。

戻り値:

  • 戻り値: 成功した場合は文字列に書き込まれた文字数 (ターミネータは含まない) を返し、失敗した場合は負の値を返します。

snprintffunction は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 関数プロトタイプ、パラメータ、戻り値

strcmp2 つの文字列が等しいかどうかを比較する関数。


プロトタイプ:

int strcmp(const char *s1, const char *s2);

パラメータ:

  • s1: 比較する最初の文字列。
  • s2: 比較する 2 番目の文字列。

戻り値:

  • 戻り値: 2 つの文字列が等しい場合は 0 を返し、最初の文字列が 2 番目の文字列より小さい場合は負の数値を返し、最初の文字列が 2 番目の文字列より大きい場合は正の数値を返します。

strcmpこの関数は、等しくない文字が見つかるか文字列の終わりに達するまで、2 つの文字列を辞書順に 1 文字ずつ比較します\02 つの文字列が等しい場合は 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.hstdio.hヘッダーstring.hファイルは文字列操作の実行に使用されることに注意してください。lstatまた、関数はシンボリック リンクを処理できるため、ファイルに関する情報を取得するには、stat関数ではなく関数がコード内で使用されますlstat

おすすめ

転載: blog.csdn.net/Goforyouqp/article/details/132232262