2012-03-18 12 views
6

ゲームサーバーを制御するプログラムを作成しています。私が作っている機能の1つは、ライブサーバーのログファイルモニターです。テキストファイルを監視してテキストボックス内のコンテンツを継続的に出力する方法

実行時にサーバーによって更新されるログファイル(単純なテキストファイル)があります。

ログファイルを継続的に確認し、その内容をRichTextBoxで出力するにはどうすればよいですか?

私はこの単純な機能を試して、ログの内容を取得しました。 もちろん、行ごとにテキストを取得し、それをテキストボックスに出力します。 また、ループが実行されている限りプログラムをロックするので、役に立たないことがわかります。

しかし、ライブモニタリングをできるだけ簡単に解決するにはどうしたらいいですか?

* EDIT *

私はPrescotsソリューションを使用しています。素晴らしいもの。

現在、私はsstreamreaderを使ってファイルからテキストをテキストボックスに入れています。問題に遭遇したのは、イベントハンドラのguiコントロールにアクセスしようとするたびに、プログラムはエラーまたは警告なしで停止したことになります。

スレッドと関係があることがわかりました。私はこのようなことを解決:

private void OnChanged(object source, FileSystemEventArgs e) 
{ 
    if (monitorTextField.InvokeRequired) 
    { 
     monitorTextField.Invoke((MethodInvoker)delegate { OnChanged(source, e); }); 
    } 
    else 
    { 
     StreamReader reader = new StreamReader("file.txt"); 

     monitorTextField.Text = ""; 
     monitorTextField.Text = reader.ReadToEnd(); 
     reader.Close(); 
     CursorDown(); 
    } 
} 

今私の唯一の問題は、私はそれにアクセスすることはできませんので、それは「別のプロセスによって使用されている」年代からfile.txtをは、サーバーによって使用されていることです。私はそのプロセスを制御することはできません..多分私は運が切れている。

しかし、serevrが実行されている間にファイルをメモ帳で開くことができるので、何らかの形でそれを可能にする必要があります。おそらく私はファイルを更新して読むときに一時ファイルのコピーを作成することができます。 Dunno ...

+0

タイマーを使用し、10秒または5秒ごとに確認してください... – SolidSnake

答えて

13

チェックアウトSystem.IO.FileSystemWatcherクラス:

public static Watch() 
{ 
    var watch = new FileSystemWatcher(); 
    watch.Path = @"D:\tmp"; 
    watch.Filter = "file.txt"; 
    watch.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite; //more options 
    watch.Changed += new FileSystemEventHandler(OnChanged); 
    watch.EnableRaisingEvents = true; 
} 

/// Functions: 
private static void OnChanged(object source, FileSystemEventArgs e) 
{ 
    if(e.FullPath == @"D:\tmp\file.txt") 
    { 
     // do stuff 
    } 
} 

編集:あなたは、ファイルに関するいくつかの詳細を知っていれば、あなたは最後の行を取得するための最もefficent方法を扱うことができます。たとえば、ファイルを読むときに、読んだものを消去することができるので、次に更新されるときに、そこにあるものを取り出して出力するだけです。おそらく、一度に1つの行が追加されていることがわかっている場合、コードはすぐにファイルの最後の行にジャンプできます。等

+0

ありがとうございました!それは多くの助けになります。私はこれに非常に新しいです...今、私は "メソッドは、戻り値の型を持っている必要があります取得するのnoobの問題に実行する、 )」。私はおそらく間違った場所や方法でそれを作成しています。私は私の "パブリック部分クラスMYPROGRAMに入れています:フォーム" – Christoffer

+0

ああええ、申し訳ありません、私はその周りのコードを超高速書き込み。ウォッチャーコードを取り除いて、コードに適切なときに置くことができます。ウォッチャーコードは、上記のWatch()関数を使用する必要はありません。 – Prescott

+0

ありがとう!私はちょうど最初の質問に新しい情報を追加しました。新しいものは何ですか? – Christoffer

0

タイマーを追加して、Timer.Tickを1秒間隔に設定してみてください。 Timer.Tickで、この関数を実行します。

private void myTimer_Tick(object sender, EventArgs e) 
{ 
    ReadLog(); 
} 
1

@Prescottが示唆しているように、FileSystemWatcherを使用してください。ファイルがサーバーによってまだ開かれている可能性があるので、適切なFileShareモード(FileShare.ReadWriteが適切と思われる)でファイルを開くことを確認してください。ファイルが別のプロセスによって使用されている間に排他的に開こうとすると、開かれた操作は失敗します。

また、少しのパフォーマンスを得るために、ファイルを読み込んだ最後の位置を覚えておき、新しい部分だけを読み取ることができます。

+0

私はStreamReaderを使用する場合、それを行うことはできますか? – Christoffer

+0

私は特定の位置を探していると思いますが、 'Position'プロパティを使って直接' FileStream'に直接アクセスしなければなりません。したがって、最初に 'FileStream'を作成し、正しい位置に移動し、ストリームの上に' StreamReader'を構築し、データを読み込み、 'FileStream'から最後の位置を再度取得します。 (私はそれを試していない、私はそれが記載どおりに動作することを願って...) – MartinStettner

3

FileSystemWatcherが最も単純な解決策ですが、実際には信頼できないことがわかりました。多くの場合、新しいコンテンツでファイルを更新できますが、FileSystemWatcherは数秒後にイベントを発生させません。

私がこれにアプローチする唯一の信頼できる方法は、System.Timers.Timerオブジェクトを使用してファイルの変更を定期的にチェックし、ファイルサイズを確認することです。 (離れてによって引き起こされるわずかなパフォーマンスの遅れから、ここでの唯一の本当の欠点

https://gist.github.com/ant-fx/989dd86a1ace38a9ac58

使用例

var monitor = new LogFileMonitor("c:\temp\app.log", "\r\n"); 

monitor.OnLine += (s, e) => 
{ 
    // WARNING.. this will be a different thread... 
    Console.WriteLine(e.Line); 
}; 

monitor.Start(); 

:私はここにこれが可能な実証小さなクラスを書かれている

ファイルサイズのチェック)は、System.Timers.Timerを使用しているため、コールバックは別のスレッドから取得されます。

WindowsフォームまたはWPFアプリケーションを使用している場合は、簡単にクラスを変更してSynchronizingObjectを受け入れることができます。これにより、イベントハンドライベントが同じスレッドから確実に呼び出されます。

0

この回答を別の投稿c# continuously read fileに使用してください。

これは非常に効率的です。ファイルサイズが変更された場合、1秒に1回確認します。

別のスレッドで実行する(または非同期コードに変換する)こともできますが、いずれの場合でもテキストをメインスレッドにマーシャルしてテキストボックスに追加する必要があります。

関連する問題