ファイル名変更、移動、削除、存在確認

その他のファイル操作

ここではファイル処理に関するその他の情報をまとめて解説します。

ファイルというのはOSや他の様々なプログラムからアクセスされる可能性があります。
他のプログラムが操作中のファイルに対する処理はエラーが発生する可能性があります。
実際のプログラムではエラー発生時の処理を適切に行う必要があります。

ファイル名変更

ファイル名を変更するにはrename関数を使用します。


#include <stdio.h>

int main()
{
    const char *file = "C:\\test.txt";
    const char *fileNew = "C:\\test_new.txt";

    if(rename(file, fileNew) == 0)
        printf("%sを%sにリネームしました。\n", file, fileNew);
    else
        printf("%sを%sにリネームできませんでした。\n", file, fileNew);

    getchar();
}
int rename(
 const char *oldname,
 const char *newname
);
ファイルoldnameの名前をnewnameに変更する。
成功した場合は0を、失敗した場合は0以外を返す。

これは簡単な関数です。
第一引数に指定したファイルの名前を、第二引数に変更するだけです。

指定した名前のファイルが既に存在する場合の動作は処理系依存です。
Windows + Visual Studioコンパイラでは関数が失敗しますが、他の環境では既存のファイルに上書き削除されるかもしれません。
実際のプログラムではあらかじめ宛先ファイルの存在をチェックする処理が必要でしょう。

rename関数はディレクトリ(フォルダ)の名前変更も可能です。


#include <stdio.h>

int main()
{
    const char *dir = "C:\\ABC";
    const char *dirNew = "C:\\DEF";

    if(rename(dir, dirNew) == 0)
        printf("%sを%sにリネームしました。\n", dir, dirNew);
    else
        printf("%sを%sにリネームできませんでした。\n", dir, dirNew);

    getchar();
}

ファイル移動

ファイル移動にもrename関数を使用します。


#include <stdio.h>

int main()
{
    const char *file = "C:\\test.txt";
    const char *fileNew = "C:\\new\\test.txt";

    if(rename(file, fileNew) == 0)
        printf("%sを%sに移動しました。\n", file, fileNew);
    else
        printf("%sを%sに移動できませんでした。\n", file, fileNew);

    getchar();
}

新しいファイル名に、別のディレクトリ(フォルダ)を含むパスを指定するだけです。
指定したディレクトリが存在しない場合は移動に失敗します。

ファイルのコピー

C言語標準関数にはファイルをコピーする関数は用意されていません。
OSの機能(API)を利用するか、自分で実装する必要があります。

実装はそう難しいものではなく、目的のファイルを1バイトずつ読み込んで宛先ファイルに書き込んでいくだけです。
以下はそのサンプルコードです。


#include <stdio.h>

//ファイルsrcをファイルdstにコピーする
//成功した場合は0を、失敗した場合は0以外を返す
int CopyFile(const char* src, const char* dst)
{
    //コピー元とコピー先が同じなら終了
    if (src == dst) {
        return 1;
    }

    FILE *fp_src, *fp_dst;
    
    //バイナリモードで開く
    if (fopen_s(&fp_src, src, "rb")) {
        return 1;
    }
    if (fopen_s(&fp_dst, dst, "wb")) {
        fclose(fp_src);
        return 1;
    }

    //戻り値
    int ret = 0;
    char c;

    //1バイトずつ読み書き
    while (fread(&c, sizeof(c), 1, fp_src) == 1)
    {
        if (fwrite(&c, sizeof(c), 1, fp_dst) < 1) {
			//戻り値が1未満の場合は
            //何らかの書き込みエラー
            ret = 1;
            break;
        }
    }
    
    if (!feof(fp_src)) {
        //コピー元がファイル終端(EOF)まで読み込めなかった
        ret = 1;
    }

    fclose(fp_src);
    fclose(fp_dst);

	if (ret) {
        //エラーが起きた場合はコピー先ファイルを削除
        remove(dst);
    }

    return ret;
}

int main()
{
    const char* src = "C:\\test.txt";
    const char* dst = "C:\\test_copy.txt";

    if (CopyFile(src, dst) == 0)
        printf("%sを%sにコピーしました。\n", src, dst);
    else
        printf("%sを%sにコピーできませんでした。\n", src, dst);

    getchar();
}

ファイルをテキストモードで開くと改行コードが自動的に置き換えられてしまうので、バイナリモードで読み書きする必要があります。
また、このコードはコピー先にすでに同名ファイルが存在する場合は上書きしてしまうので注意してください。

ファイル削除

ファイルの削除にはremove関数を使用します。


#include <stdio.h>

int main()
{
    const char *file = "C:\\test.txt";

    if(remove(file) == 0)
        printf("%sを削除しました。\n", file);
    else
        printf("%sを削除できませんでした。\n", file);

    getchar();
}
int remove(
 const char *path
);
ファイルpathを削除する。
成功した場合は0を、失敗した場合は0以外を返す。

これも単純な関数です。
ただし、ファイルをオープンしている場合はクローズしてから削除してください。

ファイルの存在確認

指定したファイルが存在するかを確認するには、fopen関数(fopen_s関数)で正常に開けるかどうかで判断できます。


#include <stdio.h>

int main()
{
    const char *file = "C:\\test.txt";
    FILE *fp;

    //fp = fopen(file, "r");
    fopen_s(&fp, file, "r");

    if(fp == NULL)
        printf("%sは存在しません。\n", file);
    else
        printf("%sは存在します。\n", file);

    fclose(fp);

    getchar();
}

このサンプルコードではファイルの存在をチェックするだけですが、例えばファイルが存在しなければ新しくファイルを作成する、ファイルが存在すれば更新モードで開く、などの処理を分岐するコードが考えられます。

stat関数を使用する方法

ファイルの存在確認にはstat関数も使用できます。
(stat関数に関してはファイルサイズの取得を参照)


#include <stdio.h>
#include <sys/stat.h>

int main()
{
    const char *file = "C:\\test.txt";
    struct stat statBuf;

    if (stat(file, &statBuf) == 0)
        printf("ファイル%sは存在します。\n", file);
    else
        printf("ファイル%sは存在しません。\n。", file);

    getchar();
}

stat関数が成功すればファイルが存在することになります。