- 締切済み
c/c++でのファイルの上書き保存について
現在cを勉強中なのですがファイル入出力に関して質問があります。 たとえばint型の2つの要素を持つ構造体 typedef struct{ int first,second; }ex; のex型の変数 datをFILE *fpにfwriteで書き込むとすると fwrite(&dat,sizeof(ex),1,fp); と書きますよね。書き込まれる位置はr+モードならファイルポインタの位置から上書き、aなら末尾から追加です。今データは残しておきたいのでwモードは考えていません。 ここで質問なのですが末尾ではなく任意のファイルポインタの位置から追加で書き込んだり、ある特定のレコードを削除したりと言う操作は不可能なのでしょうか? 今のところ、削除については削除したマークをつける方法、レコードの追加についてはテンポラリファイルに追加する前までのレコードをコピーして追加したいレコードを書いてそのあとに残りのデータをコピーした後テンポラリファイルの名前を変える、ということが考えられるのですがもっと効率のよい方法はないのでしょうか? よろしくお願いします。cで無理ならc++でもかまいません。
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- rentahero
- ベストアンサー率53% (182/342)
回答としては、 「現在のWindows・Unixの標準のファイルシステムにはそのような機能がありませんし、CやC++の標準入出力機能においては、そのような操作を想定していないので、不可能です。」 となります。 データベースシステムは、データベースファイル上に専用のファイルシステムを構築しています。 また、そのような追加削除に対応した汎用のファイルシステムを作る試みもあるようです。 しかし、どちらのケースにおいてもその場合はCまたはC++で標準で定義されている低水準の入出力関数とは別の低水準の入出力関数を用意してそこを経由してアクセスすることになります。 当然、CやC++の標準入出力の互換機能を用意したとしても、標準入出力の関数そのものにそのような機能はありませんので、中間に追加する機能や中間部分を削除する機能は結局別の関数を作成して標準ライブラリを拡張する必要があるでしょう。 ここからは蛇足ですが、多分、実際に実装するとなると、以下のようになるのではないでしょうか。 POSIX.1では、低水準入出力関数として int open(char *filename, int flags, ...); off_t lseek(int fd, off_t offset, int whence); int read(int fd, void *buf, size_t nbytes); int write(int fd, void *buf, size_t nbytes); void close(int fd); が定義されています。 ここに int insert(int fd, void *buf, size_t nbytes); →ファイルディスクリプタfdで示される現在のファイルの現在のファイル位置にnbytesのデータをbufから挿入する。挿入できたバイト数を返す。エラーの場合は-1を返し、errnoをセットする。 int delete(int fd, size_t nbytes); →ファイルディスクリプタfdで示される現在のファイルの現在のファイル位置からnbytesのデータを削除する。削除できたバイト数を返す。エラーの場合は-1を返し、errnoをセットする。 という風な関数を追加するような形になると思います。 これをさらに size_t finsert(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fdelete(size_t size, size_t nmemb, FILE *stream); という感じで高水準入出力としてラップ関数を用意することになるでしょう。 でも現実にはそのようなファイルシステムは普及していませんね。確かにあると便利かもしれません。
- NNori
- ベストアンサー率22% (377/1669)
fseek という関数を使えば位置を変えられます。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
>末尾ではなく任意のファイルポインタの位置から追加で書き込んだり、ある特定のレコードを削除したりと言う操作は不可能なのでしょうか? ファイルストリームと言われるように、CやC++で扱うファイルはシーケンシャルなものですから、途中に追加したり、一部分だけを削除(して繰り上がる)ということはできません。(そういうことを実現しようとすると結局全ての部分の移動(アクセス)が必要になります。 そういうのが望ましくない場合は、ISAMファイルみたいなものを扱うようにするか、DBにしてしまうしかないと思います。