ページ 1 / 1
大きなファイルへの追記
Posted: 2011年2月17日(木) 00:04
by ぼん
非常に大きなファイルをfopen()の追記モードで開くと失敗するのですが、
これはどうしようもないのでしょうか?
ファイルが無い状態から2GB以上の大きなファイルを作る場合は、_fseeki64()で操作すれば可能なんですが、
元からある大きなファイルに追記をする場合はfopen()の時点で失敗してしまいます。
"r"モードで開く場合は失敗しないのですが、これでは書き込みができません。
どうにか大きなファイルに追記する方法はないでしょうか?
開発環境はVisual C++ 2008です。
Re: 大きなファイルへの追記
Posted: 2011年2月17日(木) 10:33
by softya(ソフト屋)
試してませんが、Win32APIのCreateFileでライトモードでopenしてSetFilePointeでファイル末尾にシークしてから書きこめば出来ると思います。
Re: 大きなファイルへの追記
Posted: 2011年2月17日(木) 15:33
by ISLe
こちらも試してないですが、"r+"で開いて直後に_fseeki64で末尾に移動というのはどうでしょう。
Re: 大きなファイルへの追記
Posted: 2011年2月17日(木) 17:37
by ぼん
返信ありがとうございます。
>>softya(ソフト屋)さん
Win32APIのCreateFile()でファイルを開いてみましたが、
失敗しなかったので、おそらくできそうです。
ですが、ただのコンソールアプリでWin32APIを使うっていうのは、抵抗があるんですよね・・・。
引数多いですし・・・。
それに、既にfseek()やらの処理をしている部分をAPIに合わせたものに書き換えると、
結構な手間もありますし・・・。
質問を投稿してから、自分なりに考えて見ましたが、低水準入出力関数の
open()で読み込用と書き込み用の二つを用意すれば、読み書きの代用ができそうです。
fopen()だと"w"で開くと元のファイルは消えますが、open()だと書き込みモードで開いても消えないようですし、
ファイル内の移動は_lseeki64()で大丈夫そうです。
コード:
enum{
READ,
WRITE
};
・
・
・
int file_descriptor[2];
//読み込み用
if((file_descriptor[READ]=open("filename",O_RDONLY|O_TEXT))==-1){
exit(EXIT_FAILURE);
}
//書き込み用
if((file_descriptor[WRITE]=open("filename",O_WRONLY|O_TEXT))==-1){
exit(EXIT_FAILURE);
}
プログラムで書けばこんな感じです。
読み書き両用のO_RDWRというモードもあるようですが、これは失敗しました。
まだ、大きいファイルを開くテストと書き込むテストをしたぐらいなので、上手く行くとは限りませんが。
>>ISLeさん
"r+"で開いた時点でfopen()が失敗してしまうので、_fseeki64()を仕掛ける隙がありません。
恐らく、fopen()内で追記の為にファイル末尾に移動する処理が32ビットが
限界で失敗しているものと思われますが、fopen()の時点でファイルポインタが
取得できなければ_fseeki64()も使えません。
Re: 大きなファイルへの追記
Posted: 2011年2月18日(金) 01:12
by TRSGR
GCCだとfopen64なんてのもありますが、VCの類は
「Win32 API使えよ」という結論みたいですね
以前のバージョンのVC++にはコレの修正ファイルが提供されたようですが
VC++ 2008にも提供されているかは分かりませんでした。
C ランタイム ライブラリが 4 GB より大きなサイズのファイルを正常に扱えない
http://support.microsoft.com/kb/894942/ja
回避策
Win32 API のではこの問題は発生いたしません。そこで、
fopen関数/fread関数/fwrite関数/fclose関数の代わりに
CreateFile関数 /ReadFile関数/WriteFile関数/CloseHandle関数
といった Win32 API を使用します。
Re: 大きなファイルへの追記
Posted: 2011年2月18日(金) 17:35
by ぼん
〉〉TRSGRさん
やっぱり、公式的にはWin32APIを使うことになってるんですね。
正直、Win32APIって引数が多い上に、引数の意味とか覚えるのが面倒なんで
Windowsアプリを作る時以外は使いたくないんですよね。
それこそ、ファイル操作なんてわざわざ使わなくても、同じことができる訳ですし。
まぁ、使い慣れれば便利なのかも知れませんけど。
昨日から、低水準入出力関数を使ってプログラムを書き換えて見ましたが、
open()と_lseeki64()を使えば問題なさそうです。
読み書きモード(O_RDWR)など勝手にファイル末尾にシークするモードの場合は失敗するようですが、
普通の読み込みモードと書き込みモードならファイル末尾にシークしませんし、ファイルをオープンした後に、
_lseeki64()なりで移動すれば大丈夫でした。
同時に同じファイルに対して、読み込みモードと書き込みモードで開くことに関しても特に問題はないようです。
それぞれのシーク位置やらの管理が面倒になるかも知れませんが、操作しやすいように関数作るなり、
C++ならクラス化するなりすれば済む話ですね。
それでは、これにて解決とさせて頂きます。
返信して下さった皆様ありがとう御座いました。