ファイル

[C言語] ディレクトリ(フォルダ)をコピーする方法

C言語でディレクトリをコピーするには、標準ライブラリだけでは直接行えません。

そのため、POSIX APIやWindows APIを利用する必要があります。

POSIX環境では、opendir関数でディレクトリを開き、readdir関数でファイルやサブディレクトリを読み取ります。

各エントリをstat関数で確認し、ファイルであればfopenfwriteを使ってコピーします。

サブディレクトリの場合は再帰的に処理を行います。

Windows環境では、FindFirstFileFindNextFileを使って同様の処理を行います。

C言語でディレクトリをコピーする方法

必要なライブラリとヘッダーファイル

ディレクトリをコピーするためには、いくつかのライブラリとヘッダーファイルが必要です。

以下に主要なものを示します。

ヘッダーファイル説明
<stdio.h>標準入出力を扱うためのライブラリ
<stdlib.h>標準ライブラリの関数を使用するため
<string.h>文字列操作を行うためのライブラリ
<dirent.h>ディレクトリ操作を行うためのライブラリ
<sys/stat.h>ファイル属性を取得・設定するためのライブラリ

これらのヘッダーファイルをインクルードすることで、ディレクトリの操作やファイルのコピーが可能になります。

ディレクトリの読み取り

ディレクトリを読み取るには、opendirreaddirclosedir関数を使用します。

以下にサンプルコードを示します。

#include <stdio.h>
#include <dirent.h>
void readDirectory(const char *path) {
    DIR *dir;
    struct dirent *entry;
    // ディレクトリを開く
    if ((dir = opendir(path)) == NULL) {
        perror("ディレクトリを開けません");
        return;
    }
    // ディレクトリ内のエントリを読み取る
    while ((entry = readdir(dir)) != NULL) {
        printf("ファイル名: %s\n", entry->d_name);
    }
    // ディレクトリを閉じる
    closedir(dir);
}

このコードは指定されたパスのディレクトリを開き、その中のファイル名を出力します。

ファイルのコピー

ファイルをコピーするには、fopenfreadfwritefclose関数を使用します。

以下にサンプルコードを示します。

#include <stdio.h>
void copyFile(const char *source, const char *destination) {
    FILE *srcFile, *destFile;
    char buffer[1024];
    size_t bytesRead;
    // ソースファイルを開く
    if ((srcFile = fopen(source, "rb")) == NULL) {
        perror("ソースファイルを開けません");
        return;
    }
    // デスティネーションファイルを開く
    if ((destFile = fopen(destination, "wb")) == NULL) {
        perror("デスティネーションファイルを開けません");
        fclose(srcFile);
        return;
    }
    // ファイルをコピー
    while ((bytesRead = fread(buffer, 1, sizeof(buffer), srcFile)) > 0) {
        fwrite(buffer, 1, bytesRead, destFile);
    }
    // ファイルを閉じる
    fclose(srcFile);
    fclose(destFile);
}

このコードはソースファイルからデスティネーションファイルへデータをコピーします。

ディレクトリの作成

ディレクトリを作成するには、mkdir関数を使用します。

以下にサンプルコードを示します。

#include <sys/stat.h>
void createDirectory(const char *path) {
    // ディレクトリを作成
    if (mkdir(path, 0755) != 0) {
        perror("ディレクトリを作成できません");
    }
}

このコードは指定されたパスに新しいディレクトリを作成します。

再帰的なディレクトリコピーの実装

ディレクトリを再帰的にコピーするには、上記の関数を組み合わせて使用します。

以下にサンプルコードを示します。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
void copyDirectory(const char *source, const char *destination) {
    DIR *dir;
    struct dirent *entry;
    char srcPath[1024], destPath[1024];
    // ディレクトリを開く
    if ((dir = opendir(source)) == NULL) {
        perror("ディレクトリを開けません");
        return;
    }
    // ディレクトリを作成
    createDirectory(destination);
    // ディレクトリ内のエントリを読み取る
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }
        snprintf(srcPath, sizeof(srcPath), "%s/%s", source, entry->d_name);
        snprintf(destPath, sizeof(destPath), "%s/%s", destination, entry->d_name);
        if (entry->d_type == DT_DIR) {
            // サブディレクトリを再帰的にコピー
            copyDirectory(srcPath, destPath);
        } else {
            // ファイルをコピー
            copyFile(srcPath, destPath);
        }
    }
    // ディレクトリを閉じる
    closedir(dir);
}

このコードは指定されたソースディレクトリからデスティネーションディレクトリへ、再帰的にすべてのファイルとサブディレクトリをコピーします。

応用例

特定のファイル形式のみをコピーする

特定のファイル形式のみをコピーするには、ファイル名の拡張子をチェックする必要があります。

以下にサンプルコードを示します。

#include <string.h>
int hasExtension(const char *filename, const char *extension) {
    const char *dot = strrchr(filename, '.');
    if (!dot || dot == filename) return 0;
    return strcmp(dot + 1, extension) == 0;
}
void copySpecificFiles(const char *source, const char *destination, const char *extension) {
    DIR *dir;
    struct dirent *entry;
    char srcPath[1024], destPath[1024];
    if ((dir = opendir(source)) == NULL) {
        perror("ディレクトリを開けません");
        return;
    }
    createDirectory(destination);
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }
        snprintf(srcPath, sizeof(srcPath), "%s/%s", source, entry->d_name);
        snprintf(destPath, sizeof(destPath), "%s/%s", destination, entry->d_name);
        if (entry->d_type == DT_DIR) {
            copySpecificFiles(srcPath, destPath, extension);
        } else if (hasExtension(entry->d_name, extension)) {
            copyFile(srcPath, destPath);
        }
    }
    closedir(dir);
}

このコードは、指定された拡張子を持つファイルのみをコピーします。

hasExtension関数でファイルの拡張子をチェックしています。

コピー中の進捗表示

コピー中の進捗を表示するには、コピーしたバイト数を追跡し、全体の進捗を計算します。

以下にサンプルコードを示します。

#include <stdio.h>
void copyFileWithProgress(const char *source, const char *destination) {
    FILE *srcFile, *destFile;
    char buffer[1024];
    size_t bytesRead, totalBytes = 0;
    long fileSize;
    if ((srcFile = fopen(source, "rb")) == NULL) {
        perror("ソースファイルを開けません");
        return;
    }
    if ((destFile = fopen(destination, "wb")) == NULL) {
        perror("デスティネーションファイルを開けません");
        fclose(srcFile);
        return;
    }
    fseek(srcFile, 0, SEEK_END);
    fileSize = ftell(srcFile);
    fseek(srcFile, 0, SEEK_SET);
    while ((bytesRead = fread(buffer, 1, sizeof(buffer), srcFile)) > 0) {
        fwrite(buffer, 1, bytesRead, destFile);
        totalBytes += bytesRead;
        printf("進捗: %.2f%%\n", (totalBytes / (double)fileSize) * 100);
    }
    fclose(srcFile);
    fclose(destFile);
}

このコードは、ファイルのコピー中に進捗をパーセンテージで表示します。

ftell関数を使用してファイルサイズを取得し、コピーしたバイト数を追跡します。

コピー元とコピー先のディレクトリ構造の比較

コピー元とコピー先のディレクトリ構造を比較するには、両方のディレクトリを再帰的に読み取り、ファイルとディレクトリの存在をチェックします。

以下にサンプルコードを示します。

#include <stdio.h>
#include <dirent.h>
#include <string.h>
void compareDirectories(const char *source, const char *destination) {
    DIR *srcDir, *destDir;
    struct dirent *srcEntry, *destEntry;
    int found;
    if ((srcDir = opendir(source)) == NULL || (destDir = opendir(destination)) == NULL) {
        perror("ディレクトリを開けません");
        return;
    }
    while ((srcEntry = readdir(srcDir)) != NULL) {
        if (strcmp(srcEntry->d_name, ".") == 0 || strcmp(srcEntry->d_name, "..") == 0) {
            continue;
        }
        found = 0;
        rewinddir(destDir);
        while ((destEntry = readdir(destDir)) != NULL) {
            if (strcmp(srcEntry->d_name, destEntry->d_name) == 0) {
                found = 1;
                break;
            }
        }
        if (!found) {
            printf("コピー先に存在しない: %s\n", srcEntry->d_name);
        }
    }
    closedir(srcDir);
    closedir(destDir);
}

このコードは、コピー元のディレクトリに存在するが、コピー先のディレクトリに存在しないファイルやディレクトリをリストアップします。

rewinddir関数を使用して、ディレクトリの読み取り位置をリセットしています。

まとめ

C言語でディレクトリをコピーする方法について、必要なライブラリや実装方法、応用例を通じて詳しく解説しました。

ディレクトリのコピーは、ファイル操作の基本的なスキルを磨く良い機会です。

この記事を参考に、実際にコードを書いて試してみてください。

関連記事

Back to top button
目次へ