• 締切済み

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++でもかまいません。

みんなの回答

  • rentahero
  • ベストアンサー率53% (182/342)
回答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); という感じで高水準入出力としてラップ関数を用意することになるでしょう。 でも現実にはそのようなファイルシステムは普及していませんね。確かにあると便利かもしれません。

全文を見る
すると、全ての回答が全文表示されます。
  • NNori
  • ベストアンサー率22% (377/1669)
回答No.2

fseek という関数を使えば位置を変えられます。

全文を見る
すると、全ての回答が全文表示されます。
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

>末尾ではなく任意のファイルポインタの位置から追加で書き込んだり、ある特定のレコードを削除したりと言う操作は不可能なのでしょうか? ファイルストリームと言われるように、CやC++で扱うファイルはシーケンシャルなものですから、途中に追加したり、一部分だけを削除(して繰り上がる)ということはできません。(そういうことを実現しようとすると結局全ての部分の移動(アクセス)が必要になります。 そういうのが望ましくない場合は、ISAMファイルみたいなものを扱うようにするか、DBにしてしまうしかないと思います。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • C言語のfor文について

    C言語のfor文について C言語初心者です。質問させていただきます。 output.datというバイナリファイルに値を書き込みたい(100~149)のですが、どうもうまくいきません。 値が半分だけ正常に入って、あとの半分はおかしな値が入ります。 どなたか分かる方教えていただけないでしょうか。 ソース(一部分)↓ int main(){ int i,j; char output[456]; //ファイルに値を入れる for(i=0,j=100;i<456,j<556;i++,j++){ output[i]=j; } //バイナリ書き込みモードでファイルをオープン if((fp = fopen("output.dat","wb")) == NULL) { printf("<output.dat> file open error\n"); exit(1); } //値をファイルに書き込む fwrite(output,456,1,fp); fclose(fp); exit(0); }

  • int型の値をファイルに保存

    int errint(int errnum){  FILE *fp;  if((fp = fopen("error02.txt", "w+b")) == NULL){   printf("ファイルのオープンに失敗しました。\n");   exit(-1);  }  fwrite(&errnum,sizeof(errnum),1,fp);  fclose(fp); } int型の値を受け取ってファイルに 保存する関数を作ったのですが 出力されるテキストが 文字化けしていてうまく動きません。 独習C等の参考書を読んでも自分では分かりませんでした。 どこが間違っているのか教えてください。 よろしくおねがいします。

  • C言語のfwrite関数について

    現在,バイナリのデータを処理するプログラムを作成しています。 おおまかに言えば,ファイルA(バイナリモードでオープン)からバイナリでデータを読み込んできて,そのデータを処理してファイルB(バイナリモードでオープン)に書出す,のようなプログラムです。 その処理したデータを入れるデータ型にunsigned long long int型(64bit)を使用しています。 その処理データをファイルBに書出す時に,fwrite関数を用いています(例参照)。 (例) for(i=0; i<N; i++){ fwrite(&c[i], sizeof(c[i]), 1, fp); } //配列cが「unsigned long long int型」です。 //配列cは最初に"0"で初期化しています。 //fpはファイルポインタです。 しかし,本システムでunsigned long long int型が実際に使用しているのは下位32bitです。 上の例で書出した場合,上位32bitの"0"も書出されていることになるのでしょうか。 書出されたファイルのサイズを見れば,64bit全て書出されているようですが,計算間違いで32bitを超えたところまで何かデータが入っている可能性もあります。 どなたはfwrite関数に詳しい方,ご回答をよろしくお願いします。

  • 構造体の変数をバイナリモードで書き込んだのですが

    C言語初心者です。 以下の様なプログラムで構造体の変数をバイナリモードで書き込んだのですが #include "stdafx.h" struct TBL { char c; int i; }; int _tmain(int argc, _TCHAR* argv[]) { FILE *fp; TBL sample; sample.c = 'A'; sample.i = 'A'; fp = fopen("sample.dat","wb"); fwrite(&sample,sizeof(TBL),1,fp); fclose (fp); return 0; } できた”sample.dat”をダンプしてみると 41 CC CC CC 41 00 00 00 EOF となり char型のデータも4バイトデータを所有しているのですがどうしてでしょうか。

  • ファイルの大きさを調べたいのですが、、、(C言語)

    2週間前にC言語の勉強を始めたばかりです。 「あるファイルのサイズを見て、メモリを確保し、  読み出した内容をソートして、同じファイルに再び書き出す」 というプログラムを作ろうとしているのですが、 「ファイルのサイズを調べる」という時点でつまづいてしまっています。。。 適当に英数字を書き連ねたファイル(aaa.txt)を、 (fp = fopen(filename,"a+") という形で開いています。 追加読み書きするので"a+"かな? と思ったのですが、、、   //ファイルの終端に移動し、その位置を取得する   fseek(fp1, 0L, SEEK_END);   position = ftell(fp1);   printf("ファイルポインタの位置は %ld です",position); ファイルの大きさを調べるのに、この方法を試してみたのですが、 位置の値が0になってしまいます。。。 filelength(fileno(fp)); でも試してみましたが、 やっぱりファイルサイズが0と返ってきます。 何が原因なのか、何が悪いのかも判らなくて途方に暮れています。 「ここはこう書くんだよ」と、的確なご回答を戴けると幸いです。 基本的な質問で申し訳ありませんが,宜しくお願い致します。

  • DXライブラリとC言語 fwrite関数について?

    C言語(C++含む)とDXライブラリを用いてゲームプログラミングを行っています。初心者です。 今回、3次元配列をファイルとして出力したい。と下のようなプログラムを組んでみました。 しかし、上手くいきません。具体的に言うなら、配列の中身が最初の4つは訳の分からないものになり、残りは0で埋め尽くされてしまいます。 私としては、0か2、で埋め尽くされて欲しいのですが上手くいきません。 バイナリエディタで中身を覗いてみると、#include "Dxlib.h"なんて書いてある行があります。 これはおそらく、fwriteの使い方を間違っているんじゃないだろうか。なんて思って色々やってみたのですが、上手くいかないようです。 ここが間違っているのかそうでないのか、が未だにはっきりと分からないため、行き詰ってしまった感じがあります。 下のプログラムで間違っている箇所がありましたら、どこがどう間違っているのかと指摘して貰えると助かります。よろしくお願いします。 #include "Dxlib.h" int save_map(){ int map_yama_1[50][50][10]={0}; int map_yama_f1[50][50][10]={0}; /***** ランダムマップ生成 *****/ static int map_sakusei = 0; //ランダムマップを生成し終えているか、否か if ( map_sakusei ==0 ){ for (int a=0;a<50;a++){ for (int b=0;b<50;b++){ for (int c=0;c<10;c++){ map_yama_1[a][b][c] = GetRand(2); if (map_yama_1[a][b][c] == 1) map_yama_1[a][b][c] = 2; } } } FILE *fp = fopen("map_01.dat","wb"); if( fp == NULL ){ // NULLが返ってきたらエラー発生 return 0; } fwrite( map_yama_1, sizeof(map_yama_1), 1, fp ); //fwrite( map_yama_1, sizeof(int), 50*50*10, fp ); fclose(fp); } /***** map_yama_1作成終了 *****/ return 0; }

  • 構造体の文字列データをファイルへ書き込む方法は?

    構造体の文字列データをファイルへ書き込む方法として、構造体のデータを一気に書き込まずに、データ毎に書き込むことを勉強としてやってみようとしました。 数字の場合はうまくいったのですが、文字列の場合が分かりません。 ご存知の方、よろしくお願いいたします。 <数字の場合> typedef struct { int m1, m2; } Data; fwrite(&data[i].m1, sizeof(int), 1, fp); fwrite(&data[i].m2, sizeof(int), 1, fp); <文字列の場合> #include <stdio.h> typedef struct { char m1[10], m2[10]; } Data; int main() { static Data data[3] = { { "a1", "b1"}, { "c1", "d1"}, { "e1", "f1"}, }; Data data2[10]; FILE *fp; int i, n; fp = fopen("file.dat", "wb"); if (fp == NULL) return 1; for (i = 0; i < 3; i++) { fwrite(&data[i].m1, sizeof(Data.m1[10]), 1, fp); ← sizeofでエラーが出る fwrite(&data[i].m2, sizeof(Data.m2[10]), 1, fp); } fclose(fp); 以下省略

  • C言語でファイル読み書きを早くしたい。

    いつも利用させてもらって助かっています。 あるプログラムを作成しているのですが、ファイル入力の部分がネックとなってしまって、全体が使いものにならない状況に陥っています。 たくさんのデータをfread1回で読み込むことにより、読み込み速度はずいぶんと改善されましたが、まだ圧倒的に遅い状況です。システムコールを使いましたが、ほとんど改善されませんでした。 読み込み/書き込みの速度を改善する方法として,SSDメモリを使ったりする方法があると思いますが,プログラムの観点から改善できるところはないでしょうか? 下に、ファイル読み込みの部分だけ記述したコードを添付させて頂いたので、改善できる点があれば、御指摘頂けると助かります。 なお、前提として, (1)データはスタック領域だと不足するので、ヒープ領域に確保 (2)データファイルは改行無しの一連のデータ とします。 ちなみに、環境は OS   : CentOS5.3 memory   : 6GB コンパイラ : gcc です。 よろしくお願いします。 //----------------------------------------------------- //通常バージョン #include <stdio.h> #include <stdlib.h> #define SIZE (512*1024*1024) //500MB int main(void) { unsigned long int i; unsigned char *data; FILE *fp; data = (unsigned char *)malloc(SIZE); if(data == NULL) { printf("メモリが確保できません\n"); exit(EXIT_FAILURE); } fp = fopen("filein.dat", "rb"); fread( data, sizeof( unsigned char), (int)SIZE, fp ); fclose(fp); /* //表示 for( i=0; i<SIZE; i++ ){ printf("%2x", data[i]); } puts(""); */ fp = fopen("fileout.dat", "w"); fwrite( data, sizeof( unsigned char), (int)SIZE, fp); fclose(fp); free(data); return 0; } //----------------------------------------------------- //readシステムコールを使ったバージョン #include <stdio.h> #include <stdlib.h> #define SIZE (512*1024*1024) //500MB int main(void) { unsigned long int i; unsigned char *data; data = (unsigned char *)malloc(SIZE); if(data == NULL) { printf("メモリが確保できません\n"); exit(EXIT_FAILURE); } int fd; fd = open( "filein.dat" ); read( fd, data, sizeof(unsigned char)*SIZE); close(fd); /* //表示 for( i=0; i<SIZE; i++ ){ printf("%2x", data[i]); } puts(""); */ FILE *fp; fp = fopen("fileout.dat", "w"); fwrite( data, sizeof( unsigned char), (int)SIZE, fp); fclose(fp); free(data); return 0; }

  • PHPでのファイル操作

    Phpで一覧画面を作成しています。 フォームからの情報をリストごと各行でテキストファイルに書き込ませています。 管理画面で削除、変更を行いたいんですが、特定のファイルの行数を削除できないので困っています。 $garls_list = file("./dat/garls_list.php"); $fp = fopen("./dat/garls_list.php", "w"); foreach ($garls_listt as $dat_line => $new_list) { if ($dat_line == $_POST["list"]) { // 何も書き込まない→この行を削除したと同一 } else { fwrite($fp, $new_list); } } fclose($fp); これだとファイルが真っ白になってしまいます。 詳しい方がいらっしゃいましたらご教授お願いします。 . グレード この質問に補足する.

    • 締切済み
    • PHP
  • ファイル処理について

    大学の課題なのですが、何度取り組んでもエラーになるため、間違いのご指摘、または正答を教えていただけないでしょうか。 問題は以下のものです。 【問題】 ファイルから整数を読み込み,その値によってfpの読み込み位置をかえ,何度目の読み込みで0を読み込んだかを表示するプログラムを作成せよ. ファイルの内容の例 2,4,0, fpの読み込み位置を変えるにはfseekという関数を利用する. fseekの使い方: 現在の読み取り位置xだけずらすには, fseek(ファイルポインタ, x, SEEK_CUR); と記述する. STEP 1 データを一区切りで読み取る("2,"や"-4,"などの整数とコンマの組) 2 読み取ったデータに応じてfpを移動させる("2,"なら2移動,"-4,"なら-4移動) 3 0を読むまで繰り返す +++++*+++++fseek-exercise.c+++++*+++++ #include <stdio.h> int main(void){ FILE *fp; int c; int i; int count=0; char filename[60]; printf("ファイル名 :"); scanf("%s",filename); //ファイルを開く // (* ここに解答を書き加える *) while(1){ printf("読み込み前 : %ld\n",ftell(fp)); //fpから値を読む // (* ここに解答を書き加える *) printf("読み込んだ値は%dです\n",c); printf("読み込み後 : %ld\n\n",ftell(fp)); //読み込み位置をずらす // (* ここに解答を書き加える *) } printf("%d回目です.",count); fclose(fp); return(0); } // 以上になります。 自分で作ったプログラムは以下のようになりました。 #include <stdio.h> int main(void){ FILE *fp; int c; int i; int count=0; char filename[60]; printf("ファイル名 :"); scanf("%s",filename); //ファイルを開く // fp = fopen(filename,"r"); if(fp == NULL){ printf("cannot open\n"); exit(1); } while(1){ printf("読み込み前 : %ld\n",ftell(fp)); //fpから値を読む // c = fgetc(fp); printf("読み込んだ値は%dです\n",c); printf("読み込み後 : %ld\n\n",ftell(fp)); //読み込み位置をずらす // if(c > '0' || c< '9'){ i = atoi(&c); count++; if(i == 0){ break; } fseek(fp,i,SEEK_CUR); } } printf("%d回目です.",count); fclose(fp); return(0); } // どこを訂正していいのかわかりません。 どうぞ、よろしくお願いいたします。