Cでファイルのサイズをどのように決定しますか?


137

ファイルのサイズをバイト単位で知るにはどうすればよいですか?

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}

ファイルの詳細を取得するには、ライブラリ関数を使用する必要があります。Cは完全にプラットフォームに依存しないため、開発対象のプラットフォーム/オペレーティングシステムをお知らせいただく必要があります。
Chris Roberts

なんでchar* file、なんでFILE* file?-1
オスカー氏

ファイル関数はファイルパスではなくファイル記述子を受け入れる必要があるため、-1
Oscar

回答:


144

NilObjectのコードに基づく:

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

off_t fsize(const char *filename) {
    struct stat st; 

    if (stat(filename, &st) == 0)
        return st.st_size;

    return -1; 
}

変更:

  • ファイル名の引数を const char
  • 修正 struct stat変数名が欠落してい定義を。
  • 空のファイルではあいまいになるの-1代わりにエラーで戻り0ます。off_t符号付きの型なので、これは可能です。

fsize()エラー時にメッセージを印刷したい場合は、これを使用できます。

#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

off_t fsize(const char *filename) {
    struct stat st;

    if (stat(filename, &st) == 0)
        return st.st_size;

    fprintf(stderr, "Cannot determine size of %s: %s\n",
            filename, strerror(errno));

    return -1;
}

32ビットシステムでは、これをオプション-D_FILE_OFFSET_BITS=64でコンパイルする必要があります。コンパイルしないoff_tと、最大2 GBの値しか保持できません。詳細については、Linuxでの容量ファイルサポートの「LFSの使用」セクションを参照してください。


19
これはLinux / Unix固有です。質問ではOSを指定していなかったため、おそらく指摘する価値があります。
ドリューホール

1
戻り値の型をssize_tに変更して、問題なくサイズをoff_tからキャストできます。ssize_tを使用する方が理にかなっているように思われます:
Ted Percival

1
よりポータブルなコードについては、Derekによって提案されたfseek+ ftellを使用します。
Ciro Santilli郝海东冠状病六四事件法轮功

9
よりポータブルなコードについては、Derekによって提案されたfseek+ ftellを使用します。 いいえ。C標準では、バイナリファイルfseek()に対するto SEEK_ENDは未定義の動作であると明確に規定されています。 7.19.9.2 fseek関数 ...バイナリストリームfseekSEEK_END、以下のように、pの脚注234からのwhence値の呼び出しを意味的にサポートする必要はありません。リンクされたC標準の267。これは、未定義の動作としてバイナリストリームで明確にラベル付けfseekSEEK_ENDれます。。
Andrew Henle

74

使わない int。最近2ギガバイトを超えるファイルが汚れとして一般的です

使わない unsigned int。サイズが4ギガバイトを超えるファイルは、あまり一般的ではない汚れとして一般的です

IIRC標準ライブラリはoff_t、誰もが使用する必要がある、符号なし64ビット整数として定義します。16エクサバイトのファイルがぶらぶらし始めたら、数年で128ビットに再定義できます。

Windowsを使用している場合は、GetFileSizeExを使用する必要があります実際には、符号付き64ビット整数を使用しているため、8エクサバイトのファイルで問題が発生し始めます。愚かなマイクロソフト!:-)


1
私はoff_tが32ビットであるコンパイラを使用しました。確かに、これは4GBファイルがあまり一般的ではない組み込みシステム上にあります。とにかく、POSIXはoff64_tと対応するメソッドも定義して混乱を加えています。
アーロンキャンベル

私は常にWindowsを前提とする回答が大好きで、質問を批判する以外は何もしません。POSIX準拠のものを追加していただけませんか?
SS Anne、

1
@ JL2210テッドパーシバルから受け入れられた回答はposix準拠のソリューションを示しているため、明白なことを繰り返す意味がありません。私(および他の70人)は、ウィンドウに関するメモを追加し、ファイルサイズを表すために符号付き32ビット整数を使用しないことは、その上に付加価値があると考えました。乾杯
オリオンエドワーズ

30

Mattのソリューションは機能するはずですが、CではなくC ++であり、最初の指示は必要ありません。

unsigned long fsize(char* file)
{
    FILE * f = fopen(file, "r");
    fseek(f, 0, SEEK_END);
    unsigned long len = (unsigned long)ftell(f);
    fclose(f);
    return len;
}

ブレースも修正しました。;)

更新:これは本当に最良の解決策ではありません。Windowsでは4GBファイルに制限されており、GetFileSizeExまたはのようなプラットフォーム固有の呼び出しを使用するよりも遅くなる可能性がありますstat64


はい、そうすべきです。ただし、プラットフォーム固有の記述をしない非常に説得力のある理由がない限り、open / seek-end / tell / closeパターンではなく、プラットフォーム固有の呼び出しを使用する必要があります。
Derek Park、

1
返信が遅れて申し訳ありませんが、ここで大きな問題が発生しています。制限されたファイル(パスワードで保護されたファイルやシステムファイルなど)にアクセスすると、アプリがハングします。必要なときにユーザーにパスワードを要求する方法はありますか?
ジャスティン

@ジャスティン、あなたはおそらくあなたが直面している問題について具体的に新しい質問を開いて、あなたが使っているプラ​​ットフォーム、あなたがファイルにアクセスしている方法、そして振る舞いが何であるかについての詳細を提供するべきです。
デレクパーク

1
C99とC11の両方がlong intから戻りftell()ます。 (unsigned long)キャストは、関数によって既に制限されている範囲を改善しません。 ftell()エラーの場合は-1を返し、キャストで難読化されます。fsize()と同じタイプを返すことを提案しftell()ます。
chux-モニカを2014年

同意する。キャストは、質問の元のプロトタイプと一致させることでした。しかし、なぜそれをunsigned intではなくunsigned longに変換したのか思い出せません。
デレクパーク

15

**これを行わないでください(なぜですか?):

オンラインで見つけたC99標準ドキュメントの引用:「ファイル位置インジケーターをファイルの終わりに設定するfseek(file, 0, SEEK_END)と、バイナリストリーム(後続のnull文字が続く可能性があるため)または状態依存のエンコーディングのストリームに対して未定義の動作が発生します。初期シフト状態で確実に終了するわけではありません。**

エラーメッセージを送信できるように定義をintに変更してから、およびを使用fseek()ftell()てファイルサイズを決定します。

int fsize(char* file) {
  int size;
  FILE* fh;

  fh = fopen(file, "rb"); //binary mode
  if(fh != NULL){
    if( fseek(fh, 0, SEEK_END) ){
      fclose(fh);
      return -1;
    }

    size = ftell(fh);
    fclose(fh);
    return size;
  }

  return -1; //error
}

5
@mezhaka:そのCERTレポートは単に間違っています。fseekoおよびftello(またはfseekftell、あなたがして働くことができるサイズのファイルの制限と前者と幸せずに立ち往生している場合)、ファイルの長さを決定するための正しい方法です。statベースのソリューション、多くの「ファイル」(ブロックデバイスなど)では機能せず、非POSIX系のシステムに移植できません。
R .. GitHub ICEのヘルプを停止

1
これは、多くの非posix準拠システム(非常に最小限のmbedなど)でファイルサイズを取得する唯一の方法です
Earlz

9

POSIX

POSIX標準ではファイルサイズを取得するための独自のメソッドを持っています。 関数を使用する
ためにsys/stat.hヘッダーを含めます。

あらすじ

  • を使用してファイルの統計情報を取得しますstat(3)
  • st_sizeプロパティを取得します。

:サイズはに制限され4GBます。Fat32ファイルシステムでない場合は、64ビットバージョンを使用してください。

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

int main(int argc, char** argv)
{
    struct stat info;
    stat(argv[1], &info);

    // 'st' is an acronym of 'stat'
    printf("%s: size=%ld\n", argv[1], info.st_size);
}
#include <stdio.h>
#include <sys/stat.h>

int main(int argc, char** argv)
{
    struct stat64 info;
    stat64(argv[1], &info);

    // 'st' is an acronym of 'stat'
    printf("%s: size=%ld\n", argv[1], info.st_size);
}

ANSI C(標準)

ANSI Cは、直接ファイルの長さを決定する方法を提供しません。
私たちは心を使わなければならないでしょう。ここでは、シークアプローチを使用します。

あらすじ

  • を使用してファイルを最後まで探します fseek(3)
  • を使用して現在の位置を取得しftell(3)ます。

#include <stdio.h>

int main(int argc, char** argv)
{
    FILE* fp = fopen(argv[1]);
    int f_size;

    fseek(fp, 0, SEEK_END);
    f_size = ftell(fp);
    rewind(fp); // to back to start again

    printf("%s: size=%ld", (unsigned long)f_size);
}

ファイルがstdinパイプの場合。POSIX、ANSI Cは機能しません。 ファイルがパイプまたはの場合は
戻り0ますstdin

意見:代わりにPOSIX標準を使用する必要があります。なぜなら、それは64ビットをサポートしているからです。


1
struct _stat64そして__stat64()_windowsため。
Bob Stein

5

また、Windowsアプリを構築している場合は、GetFileSizeEx APIを使用してください。CRTファイルのI / Oは、さまざまなシステムでのファイル表現の特殊性のために、特にファイル長を決定するのに面倒なので、;)


5

std cライブラリの使用に問題がない場合:

#include <sys/stat.h>
off_t fsize(char *file) {
    struct stat filestat;
    if (stat(file, &filestat) == 0) {
        return filestat.st_size;
    }
    return 0;
}

24
これは標準のCではありません。POSIX標準の一部ですが、C標準ではありません。
デレクパーク


1

このコードセットを使用して、ファイルの長さを調べました。

//opens a file with a file descriptor
FILE * i_file;
i_file = fopen(source, "r");

//gets a long from the file descriptor for fstat
long f_d = fileno(i_file);
struct stat buffer;
fstat(f_d, &buffer);

//stores file size
long file_length = buffer.st_size;
fclose(i_file);

1

これを試して -

fseek(fp, 0, SEEK_END);
unsigned long int file_size = ftell(fp);
rewind(fp);

これが最初に行うことは、ファイルの最後までシークすることです。次に、ファイルポインターの場所を報告します。最後に(これはオプションです)、ファイルの先頭に巻き戻します。ご了承くださいfpバイナリストリームで必要があります。

file_sizeには、ファイルに含まれるバイト数が含まれます。(climits.hによると)unsigned long型は4294967295バイト(4ギガバイト)に制限されているため、それより大きいファイルを処理する可能性がある場合は、別の変数型を見つける必要があります。


3
これは、8年前のDerekの回答とどう違うのですか?
PP

これは、バイナリストリームでは未定義の動作であり、テキストストリームでftellは、ファイルから読み取ることができるバイト数を表す値を返しません。
Andrew Henle 2016

0

でしか動かない機能がありますstdio.h。私はそれがとても好きで、それは非常にうまく機能し、かなり簡潔です:

size_t fsize(FILE *File) {
    size_t FSZ;
    fseek(File, 0, 2);
    FSZ = ftell(File);
    rewind(File);
    return FSZ;
}

0

ファイルサイズを返すシンプルでクリーンな関数を次に示します。

long get_file_size(char *path)
{
    FILE *fp;
    long size = -1;
    /* Open file for reading */
    fp = fopen(path, "r");
    fseek(fp, 0, SEEK_END);
    size = ftell(fp); 
    fp.close();
    return 
}

1
ファイルを閉じる必要はありませんか?
ジェリージェレミア

いいえ、パスを期待する関数は嫌いです。代わりに、ファイルポインタを期待するようにしてください
オスカー氏

-3

あなたはファイルを開くことができ、ファイルの下部からの相対オフセット0に移動します

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

fseekから返される値はファイルのサイズです。

私は長い間Cでコーディングしていませんでしたが、うまくいくと思います。


12
SEEKBOTTOMのようなものを定義する必要はありません。#include <stdio.h> fseek(handle、0、SEEK_END);
sigjuice 2009年

-4

質問を見て、ftell簡単にバイト数を取得できます。

  long size = ftell(FILENAME);
  printf("total size is %ld bytes",size);

ftell引数として、ファイル名ではなくファイル記述子が必要です。
Barmar

@ Barmar、No ftellはファイル記述子を想定していませんFILE*。代わりにを想定しています。まずmanページを見てください!

アプローチは完全に間違っています。それは常にftell戻る定数0です。

この答えは完全に間違っています。1つfseek()は、ファイルの終わりをシークするために最初に使用する必要があり、また、文字列ではなくをftell()期待しているFILE *からです。あなたはあなたの答えを肉付けするのによく役立つでしょう。
オスカー氏、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.