サイズ4Gのファイルに追記をするには?


36NET  2004-12-09 23:46:19  No: 55585

はじめましていきなりサンプルソースなのですが↓
(test.txtは4G未満のサイズとします)

パターン1
p1 = fopen("test.txt", "a");
while(1){
  fprintf(p1, " ");
}
fclose(p1);

パターン2
while(1){
  p1 = fopen("test.txt", "a");
  fprintf(p1, " ");
  fclose(p1);
}

↑上記プログラムを実行すると
パターン1だとファイルはどこまでも増えつづけます
しかし
パターン2だと4Gに達した時点でエラーは起こらないのに
ファイルに追記されないという現象が発生してしまいます

typeコマンド等で無理やり回避は出来たのですがどなたか
この現象に関する何か情報を知っている人はいないでしょうか?

環境は
OS:Windows2000 + SP4
開発環境:VC++(VS6) + SP6
フォーマット:NTFS
です

よろしくお願いします


シャノン  2004-12-10 00:29:32  No: 55586

ファイルポインタってご存知ですか?
ループの中に ftell を入れて、どうなるか見て、何故そうなるのか考えてみてください。


なーめ  2004-12-10 00:58:01  No: 55587

fopen() 
の戻り値はちゃんとチェックしましょう。


シャノン  2004-12-10 01:05:15  No: 55588

ごまんなさい。オープンモード "a" でしたか。
俺の書き込みは無視してください。


シャノン  2004-12-10 01:05:29  No: 55589

> ごまんなさい。
ごめんなさい orz


なーめ  2004-12-10 02:06:45  No: 55590

4Gのファイルで追認テストしてくれる人
いないのではないかな。
大きいファイルの場合は CreateFile() を使用する。
スレッドの時も CreateFile() を使用する。
fopen のメリットは

    引数が簡単(大きく黄色で書きたい)

なだけですから。
(でも、これが重要なんだな。)

>> 俺の書き込みは無視してください。
どうして?
私は一般論として補足しただけですが。

じゃあ、あえて私が。
パターン1の、
>> ループの中に ftell を入れて(128Mに1回でいいからね。)、どうなるか見て、
>> 何故そうなるのか考えてみてください。

それから、パターン2で、
4G を超えたら、
そのファイルに対して、
今度は
fprintf(p1, "A");
で同様に書き込んでください。(ループはしなくてもいいです)

そしてそのファイルの先頭の1バイトを読み込んで表示してください。
何が入っていましたか?

え゛ー

とか言わないように。
示されている環境(Win2K/VC++6.0)は全く同じです。


36NET  2004-12-10 03:35:59  No: 55591

説明不足ですいません

ftellは戻り値がlong型なんでファイルが4Gをこえると
Cだと内部がまともに動作しないんだろうなとは思ってたんですが
実際書き込みすら出来ないとは思っていなかったもので...
(Cの関数仕様にそんな注意書きがなかったので)

こうすれば出来る出来ないではなくそこらへんの隠れ関数仕様を知っている
人がいないかなっと思って書き込みした次第です

因みに
p1 = fopen("4Gのファイル", "a");
fprintf(p1, "A");
の後にftellを実行すると1です
もう一度
fprintf(p1, "A");を実行すると2です
まあ当然オーバーフローした値が帰ってきてるってことですよね


シャノン  2004-12-10 04:10:33  No: 55592

>> 俺の書き込みは無視してください。
> どうして?

いや、オープンモード "w" かと思ってて。
それなら、パターン2は fopen するたびにファイルポインタがリセットされるからだろうなぁ、と。
申し訳ないです。

> ftellは戻り値がlong型なんでファイルが4Gをこえると
> Cだと内部がまともに動作しないんだろうなとは思ってたんですが

うーん、そんなお粗末な話なのかなぁ…
VC++ 6.0 の CRT って 64bit 非対応なんでしたっけ?
ftell が long しか返せないからオーバーフローするのは仕方ないとしても、内部ファイルポインタは 64bit のハズだから、書き込めないってのには納得がいかなかったり。

ちなみに、3.99GB のファイルを作ってパターン2で書き込みをしていったら、エクスプローラ上で見るサイズはちっとも増えなくて(3.99GB のまま)、そのうちエラー吐いて轟沈しました。


シャノン  2004-12-10 04:14:16  No: 55593

> うーん、そんなお粗末な話なのかなぁ…
> VC++ 6.0 の CRT って 64bit 非対応なんでしたっけ?

VC++ 7.1 でもお粗末な話でした。
lseek.c の 140 行目(7.1 の話なので、VC++ 6.0 ではたぶん違う)。
SetFilePointer で第3引数が NULL 固定。

なんだかなぁ。


シャノン  2004-12-10 04:17:48  No: 55594

というわけで、fopen( filename, "a" ) で開いた 4GB 以上のファイルに対して、fprintf で追記は出来ません、ということになりました。
fseek でも 4G を超えた移動は無理。
でも、fsetpos を使えば可能かもしれない。

#ちなみに、ンGB っていうファイルの実験には
#「スパースファイル」が便利です。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加