C言語関係掲示板

過去ログ

No.965 ファイル監視プログラム

[戻る] [ホームページ]
No.12450

ファイル監視プログラム
投稿者---だい(2004/02/03 20:31:27)


はじめて投稿させていただきます。

現在,ファイル監視を行うswatch 見たいなツールをC 言語で作成しようと奮闘しております。
swatch 程多機能でなくて良いので,単純に引数で指示されたファイルが更新され,ファイル中に特定の文字があった場合のみ標準出力にその旨を出力する程度のツールを作成しています。

※ 作成するプログラムはswatch のように,バックグラウンドで動作させる予定です。

while(1) にて無限ループを作成し,その中でstat 等の関数でファイルの更新日を監視することはできましたが,更新されているファイル中の特定文字を検索する部分のコーディングができずにいます。

監視するファイルはmaillog 等のログファイルですので,非常にサイズが大きくなる可能性があります。

更新をプログラムがキャッチした時点で,ファイルを開き,特定文字列の有無を確認していては非常に効率が悪いと思っています。

この部分の処理で良い案や参考となるサイトがあれば,お聞かせ願えませんか?
お願いいたします。

No.12463

Re:ファイル監視プログラム
投稿者---たいちう(2004/02/04 10:32:40)


回答ではないのですが興味あるので。思いつくままに。

> 更新をプログラムがキャッチした時点で,ファイルを開き,
> 特定文字列の有無を確認していては非常に効率が悪いと思っています。

1.監視対象のファイルはテキストファイルのみ?サイズは?
  ログということはファイルへの追記のみがされるのですか?
 
2.特定文字列の確認はどのようにされていますか?
  「非常に効率が悪い」のは、ここの確認方法が原因かも知れません。
  
3.ファイルの更新が追記のみに保証されている場合は、
  更新前のファイルサイズを覚えておけば、追記された部分だけ
  検索すれば良さそうですが。
 
4.「別のアプリケーションがファイルに書き込む処理を監視できないか?」
  という方向で検討していますか?別アプリ側の協力無しには不可能かと。
  (私が知らないだけで良い方法があるのかもしれませんが)

  
0.よく見ればOSも書いてないですね。環境を教えてね。

No.12467

Re:ファイル監視プログラム
投稿者---だい(2004/02/04 20:08:32)


だいです。

>回答ではないのですが興味あるので。思いつくままに。

早速の回答,ありがとうございます。

>> 更新をプログラムがキャッチした時点で,ファイルを開き,
>> 特定文字列の有無を確認していては非常に効率が悪いと思っています。

実はまだ,ファイルを開き,特定文字列の有無を確認し,アクションを起こす部分のコーディングは組んでないのです。組む前に良い案があれば聞きたいと思ったので・・・

>1.監視対象のファイルはテキストファイルのみ?サイズは?
>  ログということはファイルへの追記のみがされるのですか?

現在は/var/log/maillog のみの監視を考えていますので,テキストファイルのみです。サイズはメールサーバーですので,一日で大体200M 近くになります。メールログファイルですので,ご存知の通り普通にテキスト追記されます。

>2.特定文字列の確認はどのようにされていますか?
>  「非常に効率が悪い」のは、ここの確認方法が原因かも知れません。

その部分のコーディングは今は未着手です。効率の良い確認方法を教えていただきたく思っております。
  
>3.ファイルの更新が追記のみに保証されている場合は、
>  更新前のファイルサイズを覚えておけば、追記された部分だけ
>  検索すれば良さそうですが。

この部分のC 言語ロジックが思い浮かばなくて・・・

現在は下記のような処理を考えています。

while(1) {
.侫.ぅ襪旅洪憩時が以前調査したときと同じ場合はcontinue;
▲侫.ぅ襪魍き,特定文字列を探す
F団衒源列があれば特定のアクションを起こす
}

ここで,△了点で,なんらかの方法で記憶しておいた,前回開いたファイルポインタの位置から開くということができるのでしょうか?

もしかして,一度開いたファイルポインタをループ内で開きっぱなしにしておいても問題のでしょうか?

>4.「別のアプリケーションがファイルに書き込む処理を監視できないか?」
>  という方向で検討していますか?別アプリ側の協力無しには不可能かと。
>  (私が知らないだけで良い方法があるのかもしれませんが)

すいません。こちらの意味は理解できませんでした。
今回は単純にqmail が書き出すメールログをバックグラウンドで動作するC プログラムにて監視する事のみを目的としています。

  
>0.よく見ればOSも書いてないですね。環境を教えてね。

うっかりしていました。すいません。

OS: RedHat Linux 7.3
Kernel: 2.4.x 系
C 環境: gcc-2.96

これで足りるでしょうか?
何せC 言語の初心者ですので,足りなかったら申し訳ありません。
よろしくお願いします。

No.12485

Re:ファイル監視プログラム
投稿者---たいちう(2004/02/05 09:49:50)


> >回答ではないのですが興味あるので。思いつくままに。
> 早速の回答,ありがとうございます。

だから回答って言うほどのものではないですって。
特にLinuxということですので、私の知っている範囲を大きく超えそうです。
詳しい方助けてください。

> while(1) {
> (1)ファイルの更新日時が以前調査したときと同じ場合はcontinue;
> (2)ファイルを開き,特定文字列を探す
> (3)特定文字列があれば特定のアクションを起こす
> }
>
> ここで,(2)の時点で,なんらかの方法で記憶しておいた,前回開いたファ
> イルポインタの位置から開くということができるのでしょうか?

インターネットで丸付き数字等の機種依存文字は使わないようにしてください。
書き換えたら(1)の区別が付かなくなってしまいましたが。

一応確認しますが、whileの中では何らかの方法でwaitをかけてますよね?
CPUの力の限りループを回り続けるのは、それこそ非効率でしょう。

追記しかしないということですので、fseekとftellを使えば差分だけの
検索が可能と思います。

> もしかして,一度開いたファイルポインタをループ内で開きっぱなしにして
> おいても問題のでしょうか?

問題でしょう。正確にどんな問題なのかは知りませんが、少なくとも不要です。

> その部分のコーディングは今は未着手です。効率の良い確認方法を教えてい
> ただきたく思っております。

もっと効率の良い方法はあるのかもしれませんが、簡単なのは例えば、
 1.1KB読み込む。
 2.strstr。
 3.100B戻る。
戻るの意味は判りますよね?戻らずに1KBずつ読み込むと、求める文字列が
分かれてしまうとヒットしないからです。


No.12486

Re:ファイル監視プログラム
投稿者---nop(2004/02/05 10:28:27)


>while(1) {
>1.ファイルの更新日時が以前調査したときと同じ場合はcontinue;
>2.ファイルを開き,特定文字列を探す
>3.特定文字列があれば特定のアクションを起こす
>}
>
>ここで,2.の時点で,なんらかの方法で記憶しておいた,前回開いたファイルポインタの位置から開くということができるのでしょうか?

追加のみであれば、ファイルを開いた時点でファイルサイズを取得し保存しておけば、
次に開いた時はそれ以降が更新分のはずなので、
前回のファイルサイズ分seekするだけで問題ないでしょう。

>もしかして,一度開いたファイルポインタをループ内で開きっぱなしにしておいても問題のでしょうか?

開きっぱなしは問題ありです。
この手のプログラムの場合は、ファイルの排他制御が必須でしょう。
開きっぱなしでは、他のプロセスからアクセス出来なくなります。

No.12490

Re:ファイル監視プログラム
投稿者---ひっこしさかい(2004/02/05 13:28:42)


こんにちは

>現在は/var/log/maillog のみの監視を考えていますので,テキストファイルのみです。サイズはメールサーバーですので,一日で大体200M 近くになります。メールログファイルですので,ご存知の通り普通にテキスト追記されます。

>OS: RedHat Linux 7.3

LinuxなどのUNIXのOSには標準で tail というコマンドが
付いています。tail -f logfile
ってやると追加分が次々出力されます。この出力を
パイプを介して、今から作る簡単な処理プログラム
で料理するのが一番簡単かと。


No.12568

Re:ファイル監視プログラム
投稿者---かずま(2004/02/08 17:06:06)


> 一度開いたファイルポインタをループ内で開きっぱなしにしておいても問題のでしょうか?

問題ありません。

次の p1.c は 3秒に 1回 ログファイルに追加書き込みをするプログラム。
p2.c は、そのログファイルを監視するプログラムです。
端末エミュレータ(xterm, kterm, gnome-termainal, ...)を 2つ開いて、
一方で p1 を起動した後、他方で p2 を実行してみてください。
----------------------------------------
/* p1.c */
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    FILE *fp;  int i;
    for (i = 0; i < 10; i++) {
        fp = fopen("file.log", "a");
        fprintf(fp, "[%d]\n", i);
        fclose(fp);
        sleep(3);
    }
    return 0;
}
----------------------------------------
/* p2.c */
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    FILE *fp;  char buf[1024];

    fp = fopen("file.log", "r");
    for (;;) {
        if (fgets(buf, sizeof buf, fp))
            fputs(buf, stdout);
        else {
            clearerr(fp);
            sleep(1);
        }
    }
}
----------------------------------------


No.12617

Re:ファイル監視プログラム
投稿者---だい(2004/02/10 13:34:08)


こんにちわ。だいです。

>> 一度開いたファイルポインタをループ内で開きっぱなしにしておいても問題のでしょうか?
>
>問題ありません。

以前の投稿では,下記のような書き込みがありましたが,確かに実際
p2.c を動かしている間p1.c にて書き込みはできています。

> 開きっぱなしは問題ありです。
> この手のプログラムの場合は、ファイルの排他制御が必須でしょう。
> 開きっぱなしでは、他のプロセスからアクセス出来なくなります。

この例でいくと,ファイルポインタを開いたままの状態で他プロセスが対象
ファイルに書き込みができるということになりますが・・・。

ファイルの排他は必要ですが,アクセスできないことはなさそうですね。


No.12620

Re:ファイル監視プログラム
投稿者---だい(2004/02/10 13:58:49)


ファイル監視プログラムですが,結局下記のロジックにて実装しました。

while(1) {

1: ファイルの更新日時を調べる
2: 新規にファイルを開いた場合はファイルサイズを記憶してcontinue;
3: ファイルが更新されていない場合はconfinue;
4: ファイルをopen し,記憶しておいた最終ファイルサイズ(Byte) 位置jへファイルポインタを移動する
5: ファイル中に特定文字列があれば特定のアクションを行う
※ アクションを行う部分は単独処理となる為,fork にて実装
6: 読み込んだファイルサイズを記憶する
7: ファイルを閉じる
}

今のところ正常に動作しております。

皆様,多種のご助言,ありがとうございました。