5

C または C++ では、以下を使用してファイル サイズを返すことができます。

const unsigned long long at_beg = (unsigned long long) ftell(filePtr);
fseek(filePtr, 0, SEEK_END);
const unsigned long long at_end = (unsigned long long) ftell(filePtr);
const unsigned long long length_in_bytes = at_end - at_beg;
fprintf(stdout, "file size: %llu\n", length_in_bytes);

パディングまたは状況固有のその他の情報に基づいて、このコードから間違ったファイル サイズを返す可能性のある開発環境、コンパイラ、または OS はありますか? 1999 年頃に C または C++ の仕様に変更があり、このコードが特定のケースで機能しなくなった可能性はありますか?

この質問については、 flags を使用してコンパイルすることで大きなファイルのサポートを追加していると仮定してください-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1。ありがとう。

4

4 に答える 4

7

/proc/cpuinfoまたは、またはなどの検索できないファイル、/dev/stdinまたは/dev/ttyで取得したパイプファイルでは機能しませんpopen

また、そのファイルが同時に別のプロセスによって書き込まれる場合は機能しません。

Posix stat関数を使用すると、おそらくより効率的で信頼性が高くなります。もちろん、この機能はPosix以外のシステムでは使用できない場合があります。

于 2012-02-03T20:59:39.663 に答える
4

および関数はfseekftellどちらも ISO C 言語標準によって定義されています。

以下は、2011 C 規格の最新のパブリック ドラフトからのものですが、1990、1999、および 2011 の ISO C 規格は、同一ではないにしても、この分野ではすべて非常に似ています。

7.21.9.4:

ftell関数は、 stream が指すストリームのファイル位置標識の現在の値を取得します。バイナリ ストリームの場合、値はファイルの先頭からの文字数です。テキスト ストリームの場合、そのファイル位置インジケータには未指定の情報が含まれます。この情報は、ストリームのファイル位置インジケータをftell呼び出し時の位置に戻すために fseek関数で使用できます。このような 2 つの戻り値の差は、必ずしも、読み書きされた文字数の意味のある尺度ではありません。

7.21.9.2:

fseek関数は、 streamが指すストリームのファイル位置インジケーターを設定します。読み取りエラーまたは書き込みエラーが発生した場合、ストリームのエラー インジケータが設定され、fseekは失敗します。

バイナリ ストリームの場合、ファイルの先頭からの文字数で測定された新しい位置は、whenceで指定された位置にオフセットを追加することによって取得されます。whenceSEEK_SETの場合、指定された位置はファイルの先頭、SEEK_CURの場合はファイル位置指示子の現在の値、またはSEEK_ENDの場合はファイルの終わりです 。バイナリ ストリームは、 whence値がSEEK_ENDであるfseek呼び出しを意味のある形でサポートする必要はありません。

テキスト ストリームの場合、offsetはゼロであるか、offsetは同じファイルに関連付けられたストリームで以前に成功したftell関数 の呼び出しによって返された値であり、 whereceSEEK_SETです。

「shall」句のいずれかに違反すると、プログラムの動作が未定義になります。

そのため、ファイルがバイナリ モードで開かれた場合、ファイルftellの先頭からの文字数が表示されますが、fseekファイルの末尾からの相対値 ( SEEK_END) は必ずしも意味のあるものではありません。これは、バイナリ ファイルをブロック全体に格納し、最終ブロックに書き込まれた量を追跡しないシステムに対応します。

ファイルがテキスト モードで開かれた場合、オフセット 0 を使用してファイルの先頭または末尾をシークするか、以前の への呼び出しで指定された位置をシークできますftellfseek他の引数を使用した場合の動作は未定義です。これは、テキスト ファイルから読み取られる文字数がファイル内のバイト数と必ずしも一致しないシステムに対応します。たとえば、Windows で CR-LF ペア ( "\r\n") を読み取ると、1 文字しか読み取れませんが、ファイル内で 2 バイト進みます。

実際には、Unix ライクなシステムでは、テキスト モードとバイナリ モードは同じように動作し、fseek/ftell メソッドが機能します。Windowsでも動作すると思います(私の推測では、バイトオフセットが得られますが、これはテキストモードでftell呼び出すことができる回数と同じではない可能性があります)。getchar()

ftell()type の結果を返すことにも注意してくださいlong。が 32 ビットのシステムでlongは、この方法は 2 GiB 以上のファイルには使用できません。

ファイルのサイズを取得するには、システム固有の方法を使用する方がよい場合があります。とにかく fseek/ftell メソッドはstat()、Unix ライクなシステムなど、システム固有であるためです。

一方、fseekおよびは、遭遇する可能性が高いほとんどのftellシステムで期待どおりに機能する可能性があります。それが機能しないシステムがあると確信しています。申し訳ありませんが、詳細はありません。

Linux と Windows での作業で十分であり、大きなファイルに関心がない場合は、おそらく fseek/ftell メソッドで問題ありません。それ以外の場合は、システム固有の方法を使用してファイルのサイズを決定することを検討する必要があります。

また、ファイルのサイズがわかるものは、その時点でのサイズしか分からないことに注意してください。ファイルのサイズは、アクセスする前に変更される可能性があります。

于 2012-02-04T03:25:58.933 に答える
2

1)表面的には、コードは「OK」に見えます-問題はありません。

2)いいえ-fseekに影響を与える「CまたはC++仕様」はありません。Posix仕様があります:

3)「ファイルサイズ」が必要な場合、私の最初の選択肢はおそらく「stat()」です。Posixの仕様は次のとおりです。

4)メソッドに「問題が発生している」場合、最初の推測は「ラージファイルサポート」です。

たとえば、多くのOSには並列の「fseek()」および「fseek64()」APIがありました。

'役立つことを願っています..PSM

于 2012-02-03T20:58:57.903 に答える
1

POSIX では、fseek からの戻り値を「ファイルの先頭からのバイト数」と定義しています。Yourat_begは常にゼロになります (これが新しく開かれたファイルであると仮定します)。

したがって、次のように仮定します。

  1. ファイルはシーク可能です
  2. 懸念すべき並行性の問題はありません
  3. ファイル サイズは、選択した fseek/ftell バリアントで使用されるデータ型で表現できます。

その場合、コードは POSIX 準拠のシステムで動作するはずです。

于 2012-02-03T21:44:36.680 に答える