dポイントプレゼントキャンペーン実施中!

現在ファイルへのc言語でファイル書き換えを行おうとしているのですが
その部分だけ表すとこんな感じです。
※多少省いていますので括弧の数等の間違えがあっても見逃してください。
if((fp = fopen("aaa.txt", "r+")) == NULL)
;
else{
     while((ch = fgetc(fp)) != EOF){
       if(ch == '\n'){
         name[i] = '\0'
         i = 0;
         continue;
       }
       name[i] = ch;
       i++
       if(strcmp(name, name_a){
         fprintf(fp, "%s", coment);
       }
     }
}
ファイルを読み込んでいって、ある名称が見つかったらその後ろの
コメントを更新するというプログラムなのですが。
fprintfまで着ていることは確認できたのですが、なぜか値が書き換わりません。

c言語ではファイル書き換えはあまり一般的ではないということは聞いていて、
以前はすべて読み込んで、一部分を変えてすべて書き込む方法をとって
いましたが、効率が悪い気がしたのでこのやり方を試しています。

1 やり方、関数の使い方が間違っているならば正しい方法を教えてください。
2 そもそも"r+"の使い方がおかしい場合は元のやり方でやります。ただし
  "r+"の使い方が詳しく乗っているサイトが見つからなかったので、
  わかりやすいサイト等ありましたら、教えてください。
3 ファイル読み書きで検索するとf_seekなる言葉をよく見かけるのですが、
  あれを使わないとだめなんでしょうか?

1つでもいいので教えてください。

A 回答 (3件)

# 検証していないので ...


     while((ch = fgetc(fp)) != EOF){
       if(ch == '\n'){
         name[i] = '\0'
         i = 0;
         continue;
       }
       name[i] = ch;
       i++
       if(strcmp(name, name_a){
         fprintf(fp, "%s", coment);
       }

     while((ch = fgetc(fp)) != EOF){
       if(ch == '\n'){
         name[i] = '\0'
         i = 0;
         continue;
       }
       name[i] = ch;
       i++
       if(strcmp(name, name_a){
         fseek( fp, 0, SEEK_CUR );
         fprintf(fp, "%s", coment);
         fseek( fp, 0, SEEK_CUR );
       }
といった具合にして fseekで挟んでみましょう

もしくは
ftelで現在位置を取得
ファイルの先頭へfseek
元位置にfseek
書き込み
ftelで現在位置を取得
ファイルの先頭へfseek
元位置にfseek
としたほうがいいのかも ...

VC++のヘルプでは
r+/w+での読み書きのモード変更時には fsetpo/fseek/rewindのいずれかを実行しなさい
と明記されていました
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
このままの形ではできませんでしたが、
これを元に調べ、何とか作成できました。
やはりfseek等を使わないと無理みたいですね。

お礼日時:2009/04/24 21:46

基本的な考え方が間違っています。



他の回答のようにfseekで挟んだとしても「ファイルに対し、挿入や削除は出来ない」ので、単にコメントをfprintfするだけだと、とても困った事になります。

例えば、以下のようなファイルで「123の後ろに、コメント『//456789abc』を書き足す」と、どうなるでしょうか?

あいう
123
ABC
012
###
xyz

結果は

あいう
123//456789abc.###
xyz

になります。(「.」の部分は文字化けが起こる)

あいう
123//456789abc
ABC
012
###
xyz

にはなりません。

また、元のコメントが「//456789abc」だった時に、コメントを「//abc」に短くしたら、どうなるでしょうか?

あいう
123//456789abc
ABC
012
###
xyz



あいう
123//abc789abc
ABC
012
###
xyz

になります。

あいう
123//abc
ABC
012
###
xyz

にはなりません。

質問者さんの方法でうまく動くのは「書き換え前のコメントと、書き換えた後のコメントの『バイト数』が、同じ場合だけ」です。

上記のように「コメントのバイト数が変わる」と失敗します。

こういう場合は

・元のファイルを読み込みモードで開く。

・別のファイルを新規作成モードで開く。

・元のファイルから1行読み込む。

・必要ならば、読み込んだ行をメモリ上で加工(コメントを足したり、コメントを短くしたり、コメントを長くしたり、コメントを削除したりする)する。加工が必要ないなら、そのままにする。

・加工が終わった行を、新規作成したファイルに書き込む。

・元のファイルがEOFになるまで「読んで、加工して、書き込んで」を繰り返す。

・繰り返しが終わったら、両方のファイルを閉じる。

・ファイルを閉じたら、元のファイルをunlinkなどで削除する。

・新規作成して閉じたファイルをrenameなどで「元のファイルのファイル名にリネーム」する。

と言う処理をしましょう。
    • good
    • 1
この回答へのお礼

ご回答ありがとうございます。
昔このやり方を使っていたのですが、
(学校の先生がこのやり方が一般的だといっていたため)
一部分だけを書き換える場合にファイル全てを読み込ま
ない方法を探していたため、r+での実装を考えていました。
一応、No1さんの内容を参考に、サイトなどを確認しfseekで作成できました。
バイト数は合わせてあります。

お礼日時:2009/04/24 21:54

+ の付いたモードで fopen した場合, 入出力を切り替えるときには基本的に位置を設定する関数 (fseek, fsetpos, rewind) が必要です.


ただし, 入力から出力に切り替えるときには
・fflush でも OK.
・ファイルの最後まで読んでしまったときには関数を呼び出さなくてもいい.
だそうです.... と, 規格にはちゃんと書いてある.
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
詳しい説明が書いてあるサイト等を
教えていただけると助かります。

お礼日時:2009/04/24 21:47

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!