C# 使用FileSystemWatcher类来对一个日志文件的变化进行实时监测

本文介绍如何使用C#的FileSystemWatcher类实现实时监测日志文件变化,尤其适用于从第三方程序获取设备状态信息的场景。文章分享了一种处理多设备信息并发写入同一日志文件的技术方案,并提供了具体代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C# 使用FileSystemWatcher类来对一个日志文件的变化进行实时监测

2018年08月09日 13:33:01 loveljy_19901114 阅读数:1035

应用场景描述:在我的工作中,遇到这么一个情况,有一个没有源码的程序A,用来读取设备的状态信息,然后将这个状态信息写入一个txt日志文件中。我想要通过实时的读取日志文件的变化信息来将这个设备的状态信息提取出来。

发现使用C# FileSystemWatcher这个类的Changed这个事件可以很好的实现这个功能。

它在文件发生变化时可以及时的检测到这个文件。

开发过程中遇到的问题: 
1. 这个程序经常同时(时间点很近)读取多个设备的信息,而由于对日志文件的处理时间,所以经常不能触发足够的次数。例如,程序A往日志文件中同时写入10条数据,但是Changed这个事件可能只触发了5次。 
2. 由于日志文件的写操作不受我们的控制,因此,我们希望文件的读写操作可以共享

C# 控制台代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Configuration;
namespace ReadTxt{
class Program{
        private static string lastData = string.Empty;//用来表示上一次读取到的最后一条数据
        static void Main(string[] args){            
            FileSystemWatcher watcher = new FileSystemWatcher("path"));//注意:这里的path是文件夹路径,不包含文件名
            watcher.EnableRaisingEvents = true;
            watcher.IncludeSubdirectories = true;
            watcher.Changed += new FileSystemEventHandler(watcher_Changed);//文件变化时触发的事件      
        }
        private static void watcher_Changed(object sender, FileSystemEventArgs e)
        {
            (sender as FileSystemWatcher).EnableRaisingEvents = false;
            (sender as FileSystemWatcher).EnableRaisingEvents = true;//这样可以保证changed事件可以被重新触发。
            //启用一个任务线程来尽可能的减少changed事件处理时间
            System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                List<string> list = new List<string>();
                string strReg = "regularexpression";//正则表达式字符串,用于将对文件进行筛选,
                if (Regex.IsMatch(e.Name, strReg))
                {
                    lock (lastData)//锁定lastData,防止多个任务线程同时访问时造成lastData值的错乱
                    {
                        FileStream fs = File.Open("path" + e.Name, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                        StreamReader sr = new StreamReader(fs);//流读取器
                        try
                        {
                            //如果listData为空,则表示第一次读去变化的文件夹,这里我们默认读取到一个设备,具体到实际的项目中可以再更改
                            if (lastData == string.Empty)
                            {
                                string s = string.Empty;
                                while (!sr.EndOfStream)
                                {
                                    s = sr.ReadLine();
                                    lastData = s;
                                }
                            }
                            else//否则,从listData开始,取后面的所有数据加入list中
                            {
                                string s = string.Empty;
                                do
                                {
                                    s = sr.ReadLine();
                                } while (s != lastData);
                                while (!sr.EndOfStream)
                                {
                                    s = sr.ReadLine();
                                    list.Add(s);                                    
                                }
                            }                                                                                    
                            foreach (var str in list)
                            {
                                lastData = str;
                                DoWork(lastData)//这个函数可以自己写,用来处理数据                               
                            }
                        }                        
                        catch (Exception ex)
                        {
                            //。。。处理错误
                        }
                        finally
                        {
                            sr.Close();
                            fs.Close();
                        }
                    }
                }
            });
        }
    }
    }

这个代码目前能实现了我想要的功能,但是应该还有一些可以改进的地方,大家可以自己试一试,尤其是changed事件的重新触发和流文件这块。

using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using opc_Library; namespace Files { /// /// Form1 的摘要说明。 /// public class Form1 : System.Windows.Forms.Form { write_log write_log = new write_log(); private System.Windows.Forms.Label label1; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; private System.Windows.Forms.Button button1; private System.Windows.Forms.RichTextBox richTextBox1; private System.IO.FileSystemWatcher fileSystemWatcher1; private System.Windows.Forms.Button button2; private System.Windows.Forms.Label label2; /// /// 必需的设计器变量。 /// private System.ComponentModel.Container components = null; public Form1() { // // Windows 窗体设计器支持所必需的 // InitializeComponent(); // // TODO: 在 InitializeComponent 调用后添加任何构造函数代码 // } /// /// 清理所有正在使用的资源。 /// protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows 窗体设计器生成的代码 /// /// 设计器支持所需的方法 - 不要使用代码编辑器修改 /// 此方法的内容。 /// private void InitializeComponent() { this.label1 = new System.Windows.Forms.Label(); this.textBox1 = new System.Windows.Forms.TextBox(); this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.button1 = new System.Windows.Forms.Button(); this.richTextBox1 = new System.Windows.Forms.RichTextBox(); this.fileSystemWatcher1 = new System.IO.FileSystemWatcher(); this.button2 = new System.Windows.Forms.Button(); this.label2 = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.fileSystemWatcher1)).BeginInit(); this.SuspendLayout(); // // label1 // this.label1.Location = new System.Drawing.Point(8, 16); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(120, 16); this.label1.TabIndex = 0; this.label1.Text = "文件夹全路径名: "; // // textBox1 // this.textBox1.Location = new System.Drawing.Point(8, 40); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(320, 21); this.textBox1.TabIndex = 1; this.textBox1.Text = "C:\\"; // // button1 // this.button1.Location = new System.Drawing.Point(232, 8); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(96, 23); this.button1.TabIndex = 2; this.button1.Text = "浏览文件夹"; this.button1.Click += new System.EventHandler(this.button1_Click_1); // // richTextBox1 // this.richTextBox1.Location = new System.Drawing.Point(8, 88); this.richTextBox1.Name = "richTextBox1"; this.richTextBox1.Size = new System.Drawing.Size(320, 136); this.richTextBox1.TabIndex = 3; this.richTextBox1.Text = ""; // // fileSystemWatcher1 // this.fileSystemWatcher1.EnableRaisingEvents = true; this.fileSystemWatcher1.SynchronizingObject = this; this.fileSystemWatcher1.Changed += new System.IO.FileSystemEventHandler(this.fileSystemWatcher1_Changed); this.fileSystemWatcher1.Created += new System.IO.FileSystemEventHandler(this.fileSystemWatcher1_Created); this.fileSystemWatcher1.Deleted += new System.IO.FileSystemEventHandler(this.fileSystemWatcher1_Deleted); this.fileSystemWatcher1.Renamed += new System.IO.RenamedEventHandler(this.fileSystemWatcher1_Renamed); // // button2 // this.button2.Location = new System.Drawing.Point(232, 64); this.button2.Name = "button2"; this.button2.Size = new System.Drawing.Size(96, 23); this.button2.TabIndex = 5; this.button2.Text = "开始监视"; this.button2.Click += new System.EventHandler(this.button2_Click); // // label2 // this.label2.Location = new System.Drawing.Point(8, 72); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(120, 16); this.label2.TabIndex = 4; this.label2.Text = "文件系统变化情况: "; // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(6, 14); this.ClientSize = new System.Drawing.Size(336, 230);
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值