zoukankan      html  css  js  c++  java
  • C# 使用FileSystemWatcher类来对一个日志文件的变化进行实时监测

    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事件的重新触发和流文件这块。

  • 相关阅读:
    一个用于录制用户输入操作并实时回放的小工具
    Ubuntu 14.04 下安装wiznote客户端
    lombok @EqualsAndHashCode 注解的影响
    初始化数据库和导入数据
    com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver的区别 serverTimezone设定
    fastjson如何指定字段不序列化
    Mybatis 查询tinyint(1)的数据库字段时会自动转换成boolean类型
    Maven中settings.xml的配置项说明
    logback的使用和logback.xml详解
    解决Eureka Server不踢出已关停的节点的问题
  • 原文地址:https://www.cnblogs.com/grj001/p/12225180.html
Copyright © 2011-2022 走看看