• 締切済み

ファイル内のデータを1行削除する方法

いつもお世話になります。 今、ファイル操作を勉強しています。 sample.txtに下記のデータが格納されています。 【sample.txt】 --------------------- yamada.txt | 29 suzuki.txt | 25 kitamura.txt | 30 endo.txt | 32 --------------------- char *name="suzuki.txt"; sample.txtのデータがchar nameと一致する、 ファイルの行を削除し、行を詰めたいのですが どうしたらいいのでしょうか? 結果として、sample.txtが、 --------------------- yamada.txt | 29 kitamura.txt | 30 endo.txt | 32 --------------------- のように、一致したsuzuki.txtの行が削除され、 行が詰められている状態にしたいです。 どうぞよろしくお願い致します。

みんなの回答

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★アドバイス ・単純に『sample.txt』を読み込み、単純に一時ファイル『sample.tmp』に書き出す。  このときに『char name』と一致する行だけを書き出さないようにすれば良い。  その後に『sample.txt』を削除して『sample.tmp』のファイル名を『sample.txt』に  変更する方法もあります。ただし C 標準関数ではファイル名の変更する関数がなく  処理系によっては _rename() という関数があったりします。Windows 環境なら API  関数を使ってリネームできます。→MoveFile() ・今回は sample.txt のデータをメモリに一括で読み込み処理した方がいいのかも。  読み込む方法も回答者 No.1 さんのようにすべてのデータを1つのメモリ領域に  読み込む方法があります。こちらは No.1 さんのを参照。  私は行単位でメモリに格納して書き出す方を紹介します。  (1)ファイルをテキストでオープン(fopen)  (2)適当なサイズのメモリを確保(malloc)  (3)行単位で読み込む(fgets)  (4)『char name』と一致する行以外をメモリに格納(strstr)  (5)(4)でメモリが不足しているならメモリを拡張(realloc)  (6)ファイルが終わるまで(2)~(5)を繰り返す  (7)ファイルをクローズ(fclose)  こんな感じでどうですか?  今回はメモリの確保(malloc)、拡張(realloc)、解放(free)を使ってみます。 ・下に実装例を載せます。これを参考にもっと良い方法を探して下さい。 サンプル: size_t leng; size_t size = (10 * 1024); // 最初は 10 KBのメモリ量 size_t free = size; char *buff = (char*)malloc(size); char *tail = buff; char *stop = buff + size; char *name = "suzuki.txt"; // 削除するファイル名 char *mp; FILE *fp; // 確保チェック if ( buff == NULL ){  printf( "メモリが確保できません。\n" );  exit( 255 ); } // 読み込み if ( (fp = fopen("sample.txt","r")) != NULL ){  while ( fgets(tail,(int)free,fp) != NULL ){   if ( strstr(tail,name) != NULL ){    continue; // 削除ファイルなら次の読み込みへ   }   leng = strlen( tail );   tail += leng;   free -= leng;      if ( free < 1024 ){  // 空き領域が 1 KB 以下なら    leng = (10 * 1024); // メモリ量を 10 KB 増加(拡張)    size += leng;    free += leng;        if ( (mp = (char*)realloc(buff,size)) == NULL ){     printf( "メモリが足りませんでした。\n" );     free( buff ); // 安全なため     fclose( fp ); // 安全なため     exit( 255 );    }    // 再設定    leng = strlen( mp );    buff = mp;    tail = mp + leng;    stop = mp + size;   }  }  fclose( fp ); } // 書き出し if ( (fp = fopen("sample.txt","w")) != NULL ){  fputs( buff, fp );  fclose( fp ); } 最後に: ・ソースがちょっとがないですが読み取ってみて下さい。  また上記のサンプルを関数にして、ファイルから動的にメモリに読み込めるように  改良すれば今後いろいろと利用できます。今回は strstr() 部分で name に一致した  行はメモリには追加しない処理をしています。ここの処理をなくせば改良できます。 ・あと書き出しの方はメモリに読み込んだ内容を単純にファイルに出力すれば良いだけ  なので fopen、fputs、fclose の簡単な処理になっています。  name のチェックと削除はメモリに読み込み時に処理しているからです。 ・以上。realloc 関数については下の『参考URL』をどうぞ。

参考URL:
http://www9.plala.or.jp/sgwr-t/lib/realloc.html
全文を見る
すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.2

あっと、ミステイクです。 >メモリにすべて読み込んで概要行を メモリにすべて読み込んで該当行を それと(3)のstrncmpの方法ではメモリ保護エラーが出る可能性があるので、これも訂正します。なぜか分かりますか? 新しい(3)です。 (3)char nameの名前と一致する文字列がバッファにあるかを、1文字づつ比較して確認します。char name側が文字列終端(\0)に達したら一致したと判定します。途中で文字が違ったり、バッファ側が改行コード(0x0d,0x0a)だったり、バッファサイズ外に出そうになったら不一致として判定します。

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

ファイルの大きさが数十MB以下であれば、メモリにすべて読み込んで概要行を削除して書き出すのが一般的だと思います。 練習問題的な処理ではなく、実用レベルでプログラムを書くには次のような流れで処理します。 (1)ファイルサイズを調べて、読み込むバッファをmallocで確保します。読み込むサイズをバッファサイズとして記録します。 (2)ファイルをバイナリでオープンして、freadで一括バッファに読み込みます。処理ポインタにバッファの先頭アドレスを入れます。 (3)char nameの名前と一致する文字列がバッファにあるかを、strncmpでチェックします。strncmpを使う理由は、バッファ側の文字列終端(\0)が無いためです。 (4)一致したら、その行の終端である改行コード(0x0d,0x0a)をサーチします。これで、削除する行の先頭アドレスと終了アドレスが得られます。 (5)(4)の続きで、memcpy(先頭アドレス,終了アドレス+1,転送サイズ);で内容コピーをして間を詰めます。転送サイズは、バッファの終端アドレス-終了アドレスで求めます。転送後は、間を詰めたのでバッファサイズを修正します(方法は考えてみてください)。 (6)一致しなかったら、改行コード(0x0d,0x0a)をサーチして処理ポインタを次の行に移します。 (7)(3)~(6)までを処理ポインタがバッファの最後に達するまで繰り返します。 (8)読み込んだときと同じファイルをバイナリで出力オープンして、バッファの内容をバッファサイズ分ファイルに書き出します。 (注意)(4)と(6)で改行コードをサーチする場合に、バッファ終端が来るかも知れませんので、それを考慮する必要があります。 もっと高速な方法はありますが、とりあえず例として。

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

関連するQ&A

  • 同一ファイルからの文字列検索

    お世話になります。 今、ファイル処理を勉強しています。 hoge.txtに文字列が格納されています。 (hoge.txt) --------------------- suzuki yamada kimura tanaka ito suzuki kimura --------------------- hoge.txtの上の行より、下に検索を行い、 一致した場合、printf("HIT\n");と出力します。 動きは、 suzukiを検索文字列し、yamada~kimuraまで検索を行い、 もしヒットした場合、出力表示します。 suzukiが検索終了すると、次のyamadaを検索文字列として、 kimura~kimuraを検索します。 この動作を最後の行まで行えば終了です。 下記のfgets()で1行分を取得してからの 次の行への移行がわかりません。 FILE *fp; char name[256]; if( (fp =fopen( "hoge.txt", "r )) == NULL ){ return 0; } while( fgets(name, sizeof(name), fp ) != NULL ){ //ここで次の行以下とstrstr()で比較を行う } お手数をお掛けしますが、よろしくお願い致します。

  • 【C言語】テキストファイル内のデータを一行削除

    いつもお世話になっております。 ファイル操作についてご教授ください。 sample.txtに下記のデータが格納されています。 【sample.txt】 ------------------- りんご 100円 バナナ 120円 苺 150円 ------------------- この状態で、scanfで「バナナ」と入力し、 sample.txtからバナナの行を削除し、 行を詰めるようにしたいのですが、 どのようにしたらいいのでしょうか。 【流れ】 "文字を入力してください"のメッセージ。   ↓ 「バナナ」と入力。   ↓ ------------------- りんご 100円 苺 150円 ------------------- 上記のように、scanfで入力した「バナナ」の行が削除され、 行が詰められている上状態にしたいです。 超が付くほどの初心者なので、 ソースも書いていただけると幸いです。 どうぞ宜しくお願い致します。

  • vbsでtxtファイルを1行ずつ読み取って

    vbsでtxtファイルを1行ずつ読み取って 配列に格納し、メッセージボックスで表示したいです。 サンプルソースや参考サイトを教えてください。 txtファイルの中身のイメージは↓のような感じです。 shinagawa yokohama ・・・ ・・・ 大体50行位です。 配列でなければなりません。 よろしくお願いします。

  • ファイルのデーター削除

    下記のデーターが入っているabc.txtのファイルから 初めの2行を削除したいのですがよろしくお願いします。 10,aaa,100 11,bbb,200 12,ccc,200 13,ddd,300

    • 締切済み
    • PHP
  • 読込んだファイルの1行分削除したい

    氏名A 年齢 性別 出身 氏名B 年齢 性別 出身 氏名C 年齢 性別 出身  :  : というような内容のファイルを読込み、 指定した氏名の行(レコード)を全部削除するには、 どのような方法があるでしょう? /* ここから */ FILE *fp; char NAME[20]; /* 氏名 */ char AGE[3]; /* 年齢 */ char SEX[8]; /* 性別 */ char FROM[15]; /* 出身 */ char de][20]; /* 削除する氏名のレコード */ fp = fopen(FNAME, "r+"); if (fp == NULL) { __fprintf(stderr, "次のファイルが開けません: %s\n", FNAME); __return -1; } printf("削除するデータの氏名: "); gets(del); /* 検索氏名取得 */ /* ここまで */ ここまで考えたのですが、この後どうしていいのか分かりません。 環境 WinXP / Borland C++

  • テキストファイル内の指定文字が含まれる行以下を削除

    いつもお世話になります。 以下、バッチ(bat)で可能でしょうか? テキストファイル内(sample.txt)に指定文字(SA2:という文字)が必ず1行含まれていて 2行以上にはなりません。 SA2が含まれる行以下を削除し、sample1.txtという名前で保存したいです。 findstr SA2 でSA2が含まれる行を調べられるのいですが、その行を含む以下の行を 削除するというのが、どのように考えたらいいのかわかりません。 お力添え頂けますでしょうか? 宜しくお願い致します。

  • Excelからテキストファイルを読み込み、読み込んだ行を削除する方法

    Excelからテキストファイルを読み込み、読み込んだ行を削除する方法 いつもお世話になりますm(__)m Excel2003のVBAで、以下のようにテキストファイルを読み込む処理を作成しています。 Sub LoadFile() Dim intFF As Integer Dim strFILENAME As String Dim DtC, DtD, DtE As String Dim GYO As Long strFILENAME = ActiveWorkbook.Path & "\sample.txt" If Dir(strFILENAME) <> "" Then intFF = FreeFile Open strFILENAME For Input As #intFF GYO = 1 Do Until EOF(intFF) Input #intFF, DtC, DtE, DtE If DtC = 1 Then GYO = GYO + 1 Worksheets("DataSheet").Range("C" & GYO).Value = DtC Worksheets("DataSheet").Range("D" & GYO).Value = DtD Worksheets("DataSheet").Range("E" & GYO).Value = DtE End If Loop Close #intFF End If End Sub sample.txtからデータを読み込み、1個目のデータが「1」なら、DataSheetのC,D,Eの各列に、テキストファイルから読み込んだデータがセットされます。 1個目のデータが1以外なら、DataSheetにはセットされないようにしています。 そこで、読み込んだデータ(1個目のデータが「1」の行)を読み込んでDataSheetに挿入した後に、その行をsample.txtから削除したいのですが、どうすればいいかわかりません(>_<) 最終的に、処理を実行した後のsample.txtは、DataSheetにセットしたデータ以外が残るようにしたいのです。 お詳しい方、何卒ご教授のほど宜しくお願い致しますm(__)m

  • C言語 ファイル内のデータと入力したデータの重複

    テキストファイルを読み込み、入力したデータとの重複がないかどうかを調べたいのですが、 わからない点があるため、質問させていただきます。 -------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> int main() {    FILE *fp;    char datafile[];= "sample.txt";    char buff[512]; //読み込んだ1行分のデータを格納    char *data[1000]; //読み込んだデータを格納    int data_c = 0; //データの数    char str[256]; //入力された文字列を格納    int i;    int check; //重複チェック         (中略)    //ファイルを1行ずつ読み込み、その長さのメモリを確保し、値をコピー    while(fgets(buff, sizeof buff, fp) != NULL) {      data[data_c] = (char*)malloc(strlen(buff) + 1);      strcpy(data[data_c++], buff);    }         (中略)    //文字列を入力    fgets(str, 256, stdin);    check = 0;    //すでにあるデータと入力したデータの重複を調べる    for(i=0; i<data_c; i++) {      if(strcmp(data[i], str) == 0) {      check = 1;      break;      }    }         (中略) -------------------------------------------------------- 例えば読み込むファイルに5行書かれていた場合、 data[0]からdata[4]に確保したメモリの先頭アドレスが格納されますよね? ということはdata_cの値は4となるのですが、 その後のファイルデータと入力したデータの重複を調べるところで、 for(i=0; i<data_c; i++) となっており、data[0]からdata[3]までの4行分しか調べられないことになります。 なぜ、i<=data_cではなく、i<data_cとなっているのか、わかりましたら教えていただけますでしょうか。

  • データファイルの行を削除する

    掲示板のようなものを作っています。 データを、1投稿につき1行使って、項目を記号を使って分割させています。 1,こんにちは,umi,2004-4-1 みたいな感じですが、記事を1行削除するときの処理なのですが、 1,ファイルをロックして読み込み 2,削除する以外の行を$buffに入れる 3,rewindでポインタを先頭に 4,書き込み、ロック解除 のような処理をしているのですが、一番下の行に古いデータが残ってしまいます。 例えば 4,またあした,umi,2004-4-1 3,おはよう,umi,2004-4-1 2,さようなら,umi,2004-4-1 1,こんにちは,umi,2004-4-1 というデータの上から2行目を削除すると 4,またあした,umi,2004-4-1 2,さようなら,umi,2004-4-1 1,こんにちは,umi,2004-4-1 1,こんにちは,umi,2004-4-1 というふうになってしまいます。 通常、このような場合はどのように処理すればよろしいのでしょうか。 よろしくお願い致します。

    • ベストアンサー
    • PHP
  • ファイルを1行削除する

    ゲストブックに削除機能を付けたいのですが、やり方がわかりません。 入力された番号と一致する行を探し出して、削除キーと入力された番号が 同じだったら削除、としたいのですが、ファイルの一行を削除する方法がわかりません。 どのように行えば良いのでしょうか?

    • ベストアンサー
    • Perl