• ベストアンサー

C/C++ ファイル入出力操作 (長文です。)

C/C++歴4ヶ月の初心者プログラマーです。現在、 C/C++でのファイル入出力で大変困っております。 その内容というのはファイルをオープンし指定した テキストファイルに書き込む時に制限をかけたいのです。 例えば、 ファイルに書き込む内容が50行を超えた場合 1番始めに書き込まれた1行目の内容を削除して、 2行目~50行目のデータを1行繰上げて、最新のデータを 50行目に書き込んでいく処理をしたいのですが僕一人では 全くわからず先に進めない状態です。どなたかわかる方 おられますか?よろしければご伝授してください。 途中までのソースを載せておきますので宜しくお願いいたします。 Cで書いていますがC++でも方法があればお願いいたします。 /****************************** サンプルソース ******************************/ #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp //ファイルポインタの宣言 char str[] = "テスト書き込み"; if((fp=("test.txt","w"))==NULL) //ファイルオープン { exit(1); //ファイルオープンエラー時 } //ここの処理がわかりません。50行まできたら1行目を削除し //2行目~50行目を1行繰上げ、最新データを50行目に書き込み fprintf(fp,"%s\n", str); fclose(); }

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

BlueStonesです。補足質問に対する回答です。 ---------------------------------------------------------------- // 一行毎に入力する場合 while(1) {  // 一時保存用変数  char buf[ 256 ];  // 文字列の入力  gets( buf );  // 何も入力せずにEnterキーを押した場合は入力終了  if( strcmp( buf, "" ) == 0 )   break;  // Data変数に格納  strcpy( Data[ num ], buf );  num++; } ---------------------------------------------------------------- // ファイルにすでに入っているデータを参照する場合 // 注) // このプログラムは // if( (fp = fopen("test.txt","w")) == NULL ) // の記述よりも前に宣言してください // ファイルオープン(読み込み用) if( (fp = fopen("test.txt","r")) == NULL ) {  exit(1); } // ファイルの終わりが来るまで読み込み while( !feof( fp ) ) {  char *p;  // 一行の読み込み  fgets( Data[ num ], 256, fp );  // fgets()は末尾の改行も代入されるので、それを除去  p = strrchr( Data[ num ], '\n' );  if( p != NULL )  {   *p = '\0';  }  // 行数のカウント  num++; } // 最後の行が改行のみなら、それは無視する if( strcmp( Data[ num - 1 ], "" ) == 0 ) {  num--; } // ファイルクローズ fclose( fp ); ---------------------------------------------------------------- こんなのを考えてみましたが どうでしょうか(^_^)

ko-web
質問者

お礼

早速の回答ありがとうございます。こんな難しい処理をスラスラと 記述できるなんて本当にすごいし、羨ましいです。まだこの素晴らしい ソースを見て理解するには少々時間が掛かりそうですがゆっくり解析 していきたいと思います。BlueStones本当にこんな初心者の 悩みを聞いていただき感謝しています。ありがとうございました。

その他の回答 (4)

回答No.4

前提としてファイルのデータ内容が 変数に保存されているとした場合のプログラムを書いてみました。 ---------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) {  FILE *fp;  char str[] = "テスト書き込み";  char Data[ 64 ][ 256 ]; // 64行分の文字列が格納できる変数  int num = 0;  int i;  // ファイルオープン  if( (fp = fopen("test.txt","w")) == NULL )  {   exit(1);  }  /*   このコメント欄内には    Data変数に書き込み文字列を代入する処理   を記述する  */  // 書き込み文字列が50行以上のときの処理  if( num >= 50 )  {   // 繰上げる行数の計算   int shift = (num - 50) + 1;   // 下から49行分を繰上げ   memcpy( Data[ 0 ], Data[ shift ], 256 * 49 );   // 最新データを50行目に代入   strcpy( Data[ 49 ], str );   num = 50;  }  // 通常のデータの代入  else  {   // 最新データを代入   strcpy( Data[ num ], str );   num++;  }  // ファイルにデータを書き込み  for( i=0; i<num; i++)  {   fprintf( fp, "%s\n", Data[ i ] );  }  fclose( fp ); } ---------------------------------------------------------------- 理解できたでしょうか^_^; わからない箇所は、追って質問してくださいね。

ko-web
質問者

補足

返信遅くなり申し訳ございませんでした。 ご丁寧にソースまで記述していただきお手数お掛けしました。 このソースであれば4ヶ月の僕でも理解できました。 本当にありがとうございます。もう1つご質問があるのですが よろしいでしょうか? >/* >  このコメント欄内には >   Data変数に書き込み文字列を代入する処理 >  を記述する > */ このコメント内にも、もしよろしければBlueStonesさんの サンプルソースで構いませんので処理ソースお願い できますでしょうか?お手数お掛けしますがよろしくお願い いたします。

  • nshooter
  • ベストアンサー率25% (2/8)
回答No.3

1.もし、C言語で書きたいのなら、わたしなら、長さは不明ですが、 高々全部で50行しかないので、メモリにいったん読み込んでしまいます。 2.メモリに読み込む方法は、配列でも(固定エリア分メモリを食う方式)、malloc(OSにメモリくれーって頼んで、頼んだ分もらう方式。使い終わったらfreeで開放するのを忘れずに)でも状況によりけりですが、多分用途はログの処理かなんかでしょ。こだわるといくらでも長くなるので、 mallocで固定エリア確保して、それより読み込みが多ければエラーで十分だと思う。(もっといい方法は幾らもあるがその分プログラムが複雑になる、たとえばエラーにせずにさらにメモリをぶん取って処理をつづける方法もあるが、トータルでどんだけメモリをぶん取ったのか覚えておいてどこかでエラーにしないと駄目だぞ。メモリがなくなって死ぬぞ) 3.メモリに読み込む時に行数を数えておく、50行以下と51行以上では、まったく違う処理に振り分けて考えよう。 4.最後にメモリの内容をファイルに吐き出せば、良い。 5.二行目を読み込む時にすかさず、読み込んだメモリの位置を変数に覚えておいて、書き出すときはこの位置から書き出す方式もある。 6.プログラムが書いてないのは意地悪じゃなくって、こういう単純なプログラムは、用途によって、「使える・使えない」が、ううーーーんと、 違うんだ。あなたが何を重視するかによって、おのずと書くプログラムが、ひとつに決まるはず。 7.マニュアルを読むのならfseekの項も読んだ方が良い。あと、C言語ならあなたの書いたプログラムには、fopenを忘れているぞ。 8.fopenの同項目のアペンドは仕様を誤解しやすい処なので、使う必要があるのならば特に注意して使う必要がある。初心者ならば、知っていても避けた方が、無難。 9.もしWindows上のC言語ならば(Windows上で動作するDOSは関係ない)これらでも、動作はするものの独特の制限があるので、マニュアルを引く事。特にメモリ取得関係は変えないと駄目。今書いた全ての関数は別関数に移行している。Linuxとかならこの行は全く関係ないです。

ko-web
質問者

お礼

お返事遅くなり申し訳ございません。大変貴重な回答を頂き ありがとうございます。ずばりlogの処理です。 えっ!こういう処理って難易度てきに簡単な処理だったんですか? 自分では全く処理が浮かばず前に進めない状態でした・・・。 知識が全くないので、これからしっかり勉強したいと思います。 本当にアドバイスありがとうございます。nshooterさんの 貴重なアドバイスをメモしておきます。

  • nk2
  • ベストアンサー率23% (6/26)
回答No.2

C++の標準ライブラリ(STL) dequeを用いれば簡単に実装できると思う。 //---------------------------------------------------------- #include <deque> #include <string> //---------------------------------------------------------- class My_Buffer { deque<string> buf; public: void add(string& text) { if(buf.size() >= 50) buf.pop_front(); buf.push_back(text); } const deque<string>& GetBuffer() const { return buf; } }; //---------------------------------------------------------- int main() { My_Buffer buf; string text = "ABC"; for(int k=0;k < 2;k++) { for(int i=0;i < 25;i++) buf.add(text); text = "DEF"; } //const忘れないでね。 const deque<string> TEXT = buf.GetBuffer(); for(unsigned int i=0;i < TEXT.size();++i) { cout << TEXT[i] << endl; } } //---------------------------------------------------------- 何も考えずにMy_Buffer.add()に書き込む順番に文字列を渡していく。 そしてGetBufferで取得して取得した文字列配列からファイルに書き込む。

ko-web
質問者

お礼

返事が遅くなり申し訳ございませんでした。 >C++の標準ライブラリ(STL) >dequeを用いれば簡単に実装できると思う。 ご丁寧にソースまで記述していただきありがとうございます。 が、自分自身がC/C++の勉強不足で処理内容に理解しかねます。 本当にご丁寧に指導いただいているのに申し訳ございません。 印刷して理解できるまで目を通したいと思います。 貴重な回答ありがとうございました。

noname#86752
noname#86752
回答No.1

その操作は非常に厄介です。 やりたいことを簡潔に表すとファイルの最後の50行を書き込むだけなので、一度書いたファイルを操作するようなことをせずにファイルを読み込みながら最後の50行だけを保持し、ファイルを読み終わってから書き込んだほうがプログラムがすっきりすると思いますが、いかがでしょう?

ko-web
質問者

補足

お返事遅くなり申し訳ございませんでした。 貴重なアドバイスありがとうございます。 が・・・、読み込みながら最後の行だけを保持して、 ファイルを読み終わってから書き込む処理が どう処理すればよいか浮かんできません。 もしよろしければ、簡単なサンプルソースお願い できますでしょうか?わがままな質問で申し訳 ございませんがよろしくお願いいたします。

関連するQ&A

専門家に質問してみよう