現在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++でもかまいません。
A 回答 (3件)
- 最新から表示
- 回答順に表示
No.3
- 回答日時:
回答としては、
「現在の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);
という感じで高水準入出力としてラップ関数を用意することになるでしょう。
でも現実にはそのようなファイルシステムは普及していませんね。確かにあると便利かもしれません。
No.1
- 回答日時:
>末尾ではなく任意のファイルポインタの位置から追加で書き込んだり、ある特定のレコードを削除したりと言う操作は不可能なのでしょうか?
ファイルストリームと言われるように、CやC++で扱うファイルはシーケンシャルなものですから、途中に追加したり、一部分だけを削除(して繰り上がる)ということはできません。(そういうことを実現しようとすると結局全ての部分の移動(アクセス)が必要になります。
そういうのが望ましくない場合は、ISAMファイルみたいなものを扱うようにするか、DBにしてしまうしかないと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・「I love you」 をかっこよく翻訳してみてください
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・昔のあなたへのアドバイス
- ・かっこよく答えてください!!
- ・あなたが好きな本屋さんを教えてください
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ラップ関数とはどんなものですか?
-
「指定されたキャストは有効で...
-
std::set<int> で、ある値が何...
-
数値を入力して1からその数値ま...
-
#define _CRT_SECURE_NO_WARNIN...
-
構造体の勉強中です 合計点の高...
-
C言語での引数の省略方法
-
Arduinoのプログラムにエラーが...
-
【C++】関数ポインタの使い方
-
if と配列の組み合わせ
-
return 1L
-
剰余演算を論理演算と加減算に...
-
既に定義されている関数のプロ...
-
C#の質問
-
ポインタによる関数への配列渡し
-
線形補間 2次元テーブル C言語...
-
プログラミングc++
-
複数桁10進数の*桁目だけを抽出...
-
C# リストボックスに同じ文字が...
-
課題でつまってます・・・
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
#define _CRT_SECURE_NO_WARNIN...
-
AtCoderABC135の問題Cについて
-
C言語 エラーの原因がわからな...
-
複数桁10進数の*桁目だけを抽出...
-
【C++】関数ポインタの使い方
-
実数の整数部,小数部の取得
-
ラップ関数とはどんなものですか?
-
if と配列の組み合わせ
-
return 1L
-
read関数をノンブロッキングで...
-
(int *)の意味
-
std::set<int> で、ある値が何...
-
Win32APIで作るコンボボックス...
-
C++でvectorにテキストファイル...
-
「{ } で囲むだけ」は正しい?
-
足して100になるような乱数のア...
-
Arduinoのプログラムにエラーが...
-
課題でつまってます・・・
おすすめ情報