ファイルサイズの取得

ファイル処理7

ファイルサイズを取得するにはstat関数を使用します。
stat関数を使用するためにはstat構造体も使用します。
これらの使用には#include <sys/stat.h>が必要です。

ただし、これらの関数、構造体はC言語標準ではありません。


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

//適当なデータを書き込む
void Write(const char *file)
{
    FILE *fp;

    //fp = fopen(file, "w");
    fopen_s(&fp, file, "w");
    if (fp == NULL)
    {
        printf("%sのオープンに失敗しました。\n", file);
        return;
    }

    char str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n\
abcdefghijklmnopqrstuvwxyz";

    fputs(str, fp);

    fclose(fp);

    printf("%sに保存しました。\n", file);
}

//ファイルサイズを取得する
//戻り値が-1の場合は取得失敗
long GetFileSize(const char *file)
{
    struct stat statBuf;

    if (stat(file, &statBuf) == 0)
        return statBuf.st_size;

    return -1L;
}

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

    Write(file);
    size = GetFileSize(file);

    printf("%sのサイズ: %d", file, size);

    getchar();
}
C:¥test.txtに保存しました。
C:¥test.txtのサイズ: 54

ファイルは「ABC~XYZ(改行)abc~xyz」というテキストを用意しています。
(別にどんなファイルでも構いません)

なお、長すぎる文字列リテラルは\記号を挟むことで途中で改行が可能です。
サンプルコードでは改行コード(\n)の次で改行しています。

stat構造体とstat関数

int stat(
 const char *path,
 struct stat *buffer
);
文字列pathに存在するファイルから情報を取得し、stat構造体変数bufferに格納する。
関数が成功した場合は0を、失敗した場合は-1を返す。

第一引数はファイルパスの指定です。
相対パス、絶対パスのどちらでも可能です。

第二引数はstat構造体の変数へのポインタを指定します。
stat構造体はファイルに関する各種情報を持つ構造体です。
ファイルサイズのほか、ファイルへのアクセス日時や修正日時なども扱います。
ファイルサイズはst_sizeというメンバ変数(long型)に保存されます。

サンプルコードで使用しているファイルの内容はアルファベット26文字+26文字と、改行コード(Windowsのテキストモードでは2文字)のテキストファイルですから、54バイトが取得されるはずです。
UNIX系のOS(MacOS、Linux)ならば1バイト少ない53バイトです。

fseek関数とftell関数によるファイルサイズ取得

ファイルサイズの取得には、fseek関数とftell関数を利用した方法もあります。
fseek関数でファイルの終わりにファイル位置指示子をセットし、ftell関数でファイルの位置を取得すれば、それはファイルサイズを示している、というわけです。
(fseek関数とftell関数に関してはランダムアクセスを参照)

しかしこの方法は推奨されません。

まず、ファイルをバイナリモードで開いた時、fseek関数の第三引数(origin)にSEEK_ENDを指定することはできません。
この指定で正しくファイル終端に位置がセットされるかどうかはコンパイラ次第です。

テキストモードではSEEK_ENDを使用できますが、ftell関数の戻り値はfseek関数の呼び出しに使用する以外の方法は想定されていません。
ファイル位置がファイルの終端を指していても、ftell関数の戻り値は正しくファイルサイズを示しているとは限らないのです。

確実にファイルサイズを取得するならば、stat関数を利用すべきです。
ただしページ先頭にも書いた通り、stat関数はC言語標準関数ではないので、使用できないコンパイラも存在します。
また、サイズ情報はlong型で取得されるため、2GB以上のサイズの場合は正しく取得できません。
(コンパイラが対応しているなら、stat64という構造体および関数を使用することで2GB以上のファイルサイズを取得することは可能です)

どのような環境でも確実にファイルサイズを取得する方法として、ファイルを開いて先頭から終端まで1バイトずつデータを読み込んで数える、という方法があります。
しかしこれは巨大なサイズのファイルではかなり時間がかかるという欠点があり、実用的とは言い難いです。

C言語の機能にこだわらないなら、OSが提供するAPIを使った方が確実です。