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