• ベストアンサー

差分ファイルを読み込んで解析する

刻々とデータが積み重なっていくファイルを、 任意のタイミングで読み取り、解析コードに通す。 データ取得はそれと平行して続いており、 次のタイミングで行う解析では、 以前と比べて新しく取得された部分のデータだけを通す…… ということをC言語を中心としたプログラムで行いたいのですが、 何か良い方法はないでしょうか。

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

  • ベストアンサー
  • don_go
  • ベストアンサー率31% (336/1059)
回答No.1

データを積み重ねたファイルのレコード件数が一定数 以上になったら、解析用に移す為のファイル名に変更 蓄積用ファイルは0件からデータの蓄積を再開。 解析用プログラムは解析用ファイルができるのを検知 して解析処理を実行して、終了したら解析ファイルを 削除または全データの累積ファイルに追加というのは?

hiro2pzbt
質問者

補足

なるほど、ファイルを作るそばから 変更していくとは思いつきませんでした。 比較的容易に実現できそうですが、 理想は自分の好きなタイミングなんですよ。 それでも、タイミングは本質的に重要な部分ではないし、 うまく使えば活用できそうなアイデアですね。

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

その他の回答 (12)

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.13

バイト単位に読んだほうが安全かな?^^ ===== rd.c #include <stdio.h> #include <unistd.h> #include <stdlib.h> /* データが書き出されているか確認する */ int is_available(FILE *fp) { int c; clearerr(fp); if ((c = getc(fp)) == EOF) return 0; ungetc(c, fp); return 1; } /* sz バイト読み込むまで読み続け、確保したメモリに格納して返す */ void *read_bytes(FILE *fp, size_t sz) { static size_t bufsiz = 0; static unsigned char *buffer = NULL; unsigned char *p; if (sz > bufsiz) buffer = realloc(buffer, bufsiz = sz); p = buffer; while (sz > 0) { size_t rv; if ((rv = fread(p, 1, sz, fp)) == 0) { clearerr(fp); sleep(3); /* 適当な時間休む */ continue; } p += rv; sz -= rv; } return buffer; } /* 個数(int)を読んで、その個数分だけのデータ(int)を読み、標準出力に書き出す */ void read_print_data(FILE *fp) { int i, len, *pdata; len = *(int *)read_bytes(fp, sizeof len); if (len <= 0) return; pdata = read_bytes(fp, sizeof(int) * len); for (i = 0; i < len; ++i) printf("%d ", pdata[i]); } /* そのまま読む */ void read1(FILE *fp) { while (!is_available(fp)) sleep(3); printf("read1: "); read_print_data(fp); putchar('\n'); } /* ファイルをオープンし、シークしてから読む */ void read2(const char fn[], long *p) { FILE *fp = fopen(fn, "rb"); fseek(fp, *p, SEEK_SET); while (!is_available(fp)) sleep(3); printf("read2: "); read_print_data(fp); putchar('\n'); *p = ftell(fp); fclose(fp); } /* ファイルをオープンし、位置を設定してから読む */ void read3(const char fn[], fpos_t *pos) { FILE *fp = fopen(fn, "rb"); fsetpos(fp, pos); while (!is_available(fp)) sleep(3); printf("read3: "); read_print_data(fp); putchar('\n'); fgetpos(fp, pos); fclose(fp); } /* 3つの方法(オープンしっぱなし、シークする、位置指定する)で、 個数(int)・データ(int[2])のバイナリレコードを 10 回読み込んで標準出力に出す。 */ int main(void) { const int N = 10; int i; const char fn[] = "data.bin"; FILE *fp; long p; fpos_t pos; if ((fp = fopen(fn, "rb")) == NULL) { perror(fn); return 1; } p = ftell(fp); fgetpos(fp, &pos); for (i = 0; i < N; ++i) { switch (i % 6) { case 0: read1(fp); read2(fn, &p); read3(fn, &pos); break; case 1: read1(fp); read3(fn, &pos); read2(fn, &p); break; case 2: read2(fn, &p); read1(fp); read3(fn, &pos); break; case 3: read2(fn, &p); read3(fn, &pos); read1(fp); break; case 4: read3(fn, &pos); read1(fp); read2(fn, &p); break; case 5: read3(fn, &pos); read2(fn, &p); read1(fp); break; } } fclose(fp); return 0; } ==== wr.c #include <stdio.h> #include <unistd.h> /* 個数(int)、データ(int[2])のバイナリレコードを 10 回書き出す */ int main(void) { const int N = 10; int buf[2]; const int len = sizeof buf / sizeof buf[0]; const char fn[] = "data.bin"; FILE *fp; int i, j, k = 0; if ((fp = fopen(fn, "wb")) == NULL) { perror(fn); return 1; } for (i = 0; i < N; ++i) { sleep(10); /* 適当に合間を入れる */ for (j = 0; j < len; ++j) buf[j] = k++; fwrite(&len, sizeof len, 1, fp); fwrite(buf, sizeof buf[0], len, fp); fflush(fp); } fclose(fp); return 0; }

hiro2pzbt
質問者

お礼

実際にソースコードの具体例まで挙げていただき、 色々と参考になりました。 ありがとうございました。 ただ、もう少し推敲してから回答を投稿してもらっていたら、 もっと読みやすくて分かりやすいものにしていただけたかな、 と思います。

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

プログラム自体が終了するので、なくてもかまいませんけど、rd.c の main() の最後の return 0; の前で、一応 fclose(fp); しておいてください^^ どうせ、エラーチェックはあまりしてないですけど。。。 実プログラムは、しっかりとエラーチェックしてくださいませ^^

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

あれ?rd.c 中で、if 文の後に変数宣言してるのに、gcc は通したな。。今は、C言語でも、ブロックの先頭じゃなきゃいけないことはなくて、どこでも変数宣言できるのか?^^ でも、まあ、一応、入れ替えておいてください。 ==== rd.c の main() の中の部分 FILE *fp; long p = 0; fpos_t pos; if ((fp = fopen(fn, "rb")) == NULL) { perror(fn); return 1; } fgetpos(fp, &pos);

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

ん。。socket() と select() の組み合わせのほうが、セマフォなんかよりポータビリティがあって、シグナルなんかより安全確実かもしれませんね^^ ではでは。ながらく失礼しました(笑)

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

>『同期を取る必要があって、…いろいろありますよね^^』 あぁ、データはファイル渡しなんだから、同期だけ取れればよいのか^^ 同期のためのファイル(空ファイルでいい)を決めておいて、そのファイルが存在するか存在しないかで同期をとってもいいですね。セマフォ・シグナルなどなどのプロセス間通信をつかってもいいですけど^^

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

あと、読み込む側が他にも仕事があるなら、最初の fread() で 0 が返ってきて EOF だったら、まだ書き出す側が書き込んでないと判定して、読み込む側が他の仕事をすればいいんじゃないですかね。

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

あっ。。read1、read2、read3 の二つ目の fread() の戻り値 sz が 0 のときは clearerr() を呼んでおいたほうがいいですね^^ 失礼しました。 ほんとは、fread() などが 0 を返したとき、無条件で clearerr() を呼ばず、エラーかEOFかを feof() で調べるのがいいと思いますけど。。。 あと、CPU の無駄遣いを防止するため、EOF ならちょっと sleep() を入れておくとか^^

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

ご参考: 先の※の条件でよければ、前に書いた3つの方法でもできますけどね^^ 同期を取る必要があって、プロセスに親子関係があるなら、パイプでくっつけておくとか、シグナルを送る(お薦めしませんが^^)とか。親子関係などなければ、セマフォを使って共有メモリを使うとか(データ量が少ないならメッセージキューとか)いろいろありますよね^^ === wr.c #include <stdio.h> #include <unistd.h> int main(void) { const int N = 10; int buf[2]; const int len = sizeof buf / sizeof buf[0]; const char fn[] = "data.bin"; FILE *fp; int i, j, k = 0; if ((fp = fopen(fn, "wb")) == NULL) { perror(fn); return 1; } for (i = 0; i < N; ++i) { sleep(10); for (j = 0; j < len; ++j) buf[j] = k++; fwrite(&len, sizeof len, 1, fp); fwrite(buf, sizeof buf[0], len, fp); fflush(fp); } fclose(fp); return 0; } ==== rd.c #include <stdio.h> #include <unistd.h> #include <stdlib.h> void read1(FILE *fp) { int len; size_t sz; printf("read1: "); while (fread(&len, sizeof len, 1, fp) == 0) clearerr(fp); while (len > 0) { int i; int buf[10]; size_t nbuf = sizeof buf / sizeof buf[0]; sz = fread(buf, sizeof buf[0], nbuf > len ? len : nbuf, fp); for (i = 0; i < sz; ++i) printf("%d ", buf[i]); len -= sz; } putchar('\n'); } void read2(const char fn[], long *p) { int len; size_t sz; FILE *fp = fopen(fn, "rb"); fseek(fp, *p, SEEK_SET); printf("read2: "); while (fread(&len, sizeof len, 1, fp) == 0) clearerr(fp); while (len > 0) { int i; int buf[10]; size_t nbuf = sizeof buf / sizeof buf[0]; sz = fread(buf, sizeof buf[0], nbuf > len ? len : nbuf, fp); for (i = 0; i < sz; ++i) printf("%d ", buf[i]); len -= sz; } putchar('\n'); *p = ftell(fp); fclose(fp); } void read3(const char fn[], fpos_t *pos) { int len; size_t sz; FILE *fp = fopen(fn, "rb"); fsetpos(fp, pos); printf("read3: "); while (fread(&len, sizeof len, 1, fp) == 0) clearerr(fp); while (len > 0) { int i; int buf[10]; size_t nbuf = sizeof buf / sizeof buf[0]; sz = fread(buf, sizeof buf[0], nbuf > len ? len : nbuf, fp); for (i = 0; i < sz; ++i) printf("%d ", buf[i]); len -= sz; } putchar('\n'); fgetpos(fp, pos); fclose(fp); } int main(void) { const int N = 10; int i; const char fn[] = "data.bin"; FILE *fp; if ((fp = fopen(fn, "rb")) == NULL) { perror(fn); return 1; } long p = 0; fpos_t pos; fgetpos(fp, &pos); for (i = 0; i < N; ++i) { switch (i % 6) { case 0: read1(fp); read2(fn, &p); read3(fn, &pos); break; case 1: read1(fp); read3(fn, &pos); read2(fn, &p); break; case 2: read2(fn, &p); read1(fp); read3(fn, &pos); break; case 3: read2(fn, &p); read3(fn, &pos); read1(fp); break; case 4: read3(fn, &pos); read1(fp); read2(fn, &p); break; case 5: read3(fn, &pos); read2(fn, &p); read1(fp); break; } } return 0; } ==== 実行結果 % gcc -o wr wr.c % gcc -o rd rd.c % ./wr & sleep 2; ./rd [1] 2592 read1: 0 1 read2: 0 1 read3: 0 1 read1: 2 3 read3: 2 3 …途中略… read3: 16 17 read2: 18 19 read3: 18 19 read1: 18 19

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

「…次のタイミングで何もせずに fp から読み出す」で、何もせずにではなくて、「もし前回のタイミングで EOF まで読んでいたら clearerr(fp) で EOF フラグを消してから」ですね^^ それと、 ※ 読み込むデータのバイト数は事前に決まっている(あるいは、何バイトか読めば書いてあるので、そのバイト数だけ読めばよい)ので、読み込む側のプログラムは、任意のタイミングで読んでも、決まったバイト数読み込めるまで読めばよいので、データを書き出すプログラムが書き出し中でもかまわない。 みたいな条件があるんですか?^^

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

『生成されるファイルは、…追加されていくだけ…。ただバイナリファイルなので、…』とありましたが、<stdio.h> の FILE *fp を使って読み書きしてるとして、  ・前回のタイミングで読んだときに fp をクローズしないでそのままにしておき、次のタイミングで何もせずに fp から読み出す とか、  ・前回のタイミングで読み終わったとき、p = ftell(fp); fclose(fp); し、次のタイミングで fp = fopen(fname, "rb"); fseek(fp, p, SEEK_SET); して fp から読み出す とか、  ・前回のタイミングで読み終わったとき、fgetpos(fp, &pos); fclose(fp); し、次のタイミングで fp = fopen(fname, "rb"); fsetpos(fp, &pos); して fp から読み出す とかでよいということですか??

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

関連するQ&A

  • EXEファイルの解析

    ちょっと前に日本語プログラム言語「なでしこ」を使用して作成したEXEファイルですが… 何の実行ファイルかわからくなりました。 あと、修正もしたいので解析できるフリーソフトがあれば、紹介していただきたいです。 よろしくお願いいたします。

  • ファイル操作について、テキストファイルの書き換え

    よろしくお願いします。 データファイルAからデータを取得して、テキストファイルBの内容の一部を取得したデータで書き換えるという操作を行うプログラムを作りたいです。 具体的には、 データファイルA[A.txt]の中身 111 222 333 444 テキストファイルB[B.txt] 文字列1="123" 文字列2="234" 文字列3="345" 文字列4="456" というような二つのファイルを読み込み、B.txtの""で囲まれた部分を、A.txtで取得したデータで置き換えるような操作を行いたいのですが・・。 使用する言語としてはスクリプト言語であるperl、もしくはプログラム作成経験があるCを使用しようと思っています。(perlは未経験で入門書を読んでいるレベル)

    • ベストアンサー
    • Perl
  • Visual Basicでファイル内の文字コード変換をしたいのです。

    こんばんは。どなたかアドバイスをお願いいたします。 実は、次の内容のプログラムをVisual Basic5.0を使って作成しようとしています。 (1)EBCDIC→JISへのコード変換(汎用機用のデータをパソコンで使用するため) (2)上記データ内に含まれるパック数字をアンパック数字に変換 (3)対象のデータをCSVファイルに書き込む ※使用する汎用機、パソコンは両方ともNEC製です。 データ数が多いことと、桁数の異なるレコードが結合されて1つのファイルとなっているため、コンバートソフトは使用できませんでした。 実は、上記(1)~(3)を行うプログラムがあるのですが、作成者が知らないうちに変更してしまったらしく、動かなくなっていました。作成者は現在すでに退職しており連絡も取れません。そのプログラムはVisual C++で作成されているため現在の私の力では解析して変更点を直すができませんでした。急を要するためVisual C++を勉強して解析するか、Visual Basicで作り直すかの選択を迫られている状態です。プログラム言語により処理が可能なものと不可能なものがあると聞いたことがあるのですが、Visual Basicで作成できればそちらに切り替えたいと考えています。長文になり申し訳ありません。何卒よろしくお願いします。

  • 入力ファイルの解析

    fp=fopen(ex1.cpp,"r"); によって、開いたCソースファイルを解析してコンパイルエラーがあるかを確かめるプログラムを作成するにはどうすればいいのですか?

  • 別ファイルの内容を検索したいのですが、(超初心者です)

    現在、独学でC言語を勉強しているのですが、 別のファイル(.dat)にあるデータの内容を 該当するデータだけ表示させたいのですが、 どうやったらできるのかわかりません。。 例えば、、、 別ファイルの内容が、 145556 1 C言語 256885 2 C言語その1 456789 3 C言語その2     : という風になっていたとして、 プログラム実行中に 145556 と入力したら C言語 と表示されるような 行ごとに入力されたデータの最初の6桁を検索して 必要な部分だけを表示することはできるのでしょうか? もし、できるのであれば どのようにプログラムを作成すればいいのか教えてください! そして、勝手なのですが、勉強中なので  どうして そうなるのかも教えて欲しいのです。 よろしくお願いします。

  • 音を解析???

    専門学校生です。 PICNICを使った課題が出されました。 PICNICを使ったものなら何でもよく、音声処理に興味があるので、音関連のものを作りたいと思っています。 そこで次のようなものを考えたのですが、作れるものなのかどうかを教えていただきたいです。(一番プログラムが不安です) マイクに人の声でドレミと入力したら、スピーカーから楽器の音でドレミと出てくるもの作りたいと思います。 詳しく説明しますと、ドレミという音の高さの声をマイクに入力。その音をPCで解析し、スピーカーから楽器の音でドレミと出てくるようにしたいです。 PICNICも使わなければならない課題なので、どこかで使わないといけません。(マイクもしくはスピーカーと、PCの間にでも使おうかと) 音を解析するにはプログラムを使って、入力音声を、ある周波数ごとに区切りそれを出力しようと思います。 C言語で簡単なソート、リストのプログラムくらいは作れます。C言語を習って来たのですが、別の言語のほうが作りやすそうならそちらの言語を学ぼうかと思います。 四人一班で、製作時間は長くて30時間~40時間くらいの予定です。 そこで質問です。 (1)このようなものは自分たちに作れそうですか?  無理そうなら他のものを作ろうかと思います。 (2)プログラミング言語としてはどのような言語がいいでしょうか?  プログラムもどこから手をつけていいかまったくわかないので、手のつけ方を教えていただきたいです。 (3)作成にあたってアドバイスなどお願いします。  参考になりそうなサイト、書籍等があれば教えていただきたいです。

  • web上のhtmlファイルから文字データを取得するには

    c言語を勉強中の初心者です、 自分が今作りたいプログラムはweb上のhtmlにある文字データを取得し、 整理し、プログラム内で表示するような物ですが、どの本を読んでもweb上からデータを取得する方法が紹介されていません、(見つけられないだけかもしれませんが…) 例えば、yahooの株情報からデータを取得するソフトなんてのはよくありますよね? こういった方法は何か凄く特殊なのでしょうか? 一般的にこういった事をプログラミング用語で何と呼ぶのかすらわからないので、検索で調べようがありません… ただweb上のhtmlファイルから文字列を取得したいだけです、 コードの例などを紹介している書籍やwebページを教えてください よろしくお願いします。

  • 大容量のテキストファイルの内容を解析について

    10000行1GBほどの大容量のテキストファイルの内容を解析しようとしています。 このテキストファイルは約20行で一塊のデータが入っており、次の20行からまた一塊のデータがはいっています。現在、全行を1行ごとにArrayListに格納してから 各行にキーワードが含まれていないかチェックし、含まれていたらそのデータの塊の中にある2行目を行を出力しようとしています。 しかし、10000行のArrayListを宣言しようとしたところ、途中でOutOfMemoryになり、メモリ不足になります。そこで、最初の20行を読み込み、処理をし、次の20行を読み込み処理をする・・・と考えているのですが、このようなことをJAVAのソースコードで実現することは可能でしょうか?? 皆さんは大容量ファイルを解析するときにどのような手法をとっていますか? ご教示いただければ幸いです。

    • ベストアンサー
    • Java
  • ファイルの置換えはできますか?

    以前、自分以外の人がC言語でプログラムを作って、 C言語のソースファイルなのですが それを内容はそのままでC++のソースファイルに置換える事は可能でしょうか?

  • ゲームの解析のプログラムについて

    自分は、C#でパソコンのゲームの改造コードを解析するプログラムを作成しています。 ただ、そこでわからないことがありまして まずROMを読み込んで、動いているメモリアドレス(16進数)を検索する機能をつけたいんですがどうすれば良いでしょうか? 例えば、キャラクターが動いたら変化した座標や位置データを調べるようにしたいんですが

都会と田舎 幸せ
このQ&Aのポイント
  • 都会と田舎の幸せを比較すると、都会では楽しいことが多いですが、高いお金がかかります。一方、田舎では安く生活できますが、不便な面もあります。
  • 田舎での生活は安くてゆったりとしている一方、都会での生活は刺激的で楽しいものが多いです。しかし、都会には高いお金がかかり、節約が必要になります。
  • 趣味や物を買わない人にとっては、田舎でのボーッとした生活も幸せかもしれません。しかし、何か特別な経験や刺激を求める場合には、都会がより幸せな選択になるかもしれません。
回答を見る