C# FileSystemWatcher - 多个事件
Posted
技术标签:
【中文标题】C# FileSystemWatcher - 多个事件【英文标题】:C# FileSystemWatcher - multiple events 【发布时间】:2021-08-13 20:10:12 【问题描述】:我创建此 Windows 服务,当文件 .txt/.csv 出现在特定文件夹中时,获取此文件并将第一行放入数据库中一次。问题是,一旦服务启动,事件处理程序“处理”仅 1 次添加文件,事实上,当我删除文件并尝试放置另一个文件时,服务不会在数据库中添加数据,我必须手动重新启动它。我需要的解决方案是,该服务一旦启动,就会保持活动状态,并创建一个像服务一样运行的文件系统观察器(/eventhandler),每次添加新文件时,它都会将第一行插入数据库
namespace myServiceDB_D1
public partial class ServiceD1 : ServiceBase
public ServiceD1()
InitializeComponent();
Timer mainTimer = new Timer(); // name space(using System.Timers;)
public static FileSystemWatcher watcher;
protected override void OnStart(string[] args)
WriteToFile("Service is started at " + DateTime.Now);
mainTimer.Elapsed += new ElapsedEventHandler(main);
mainTimer.Interval = 2 * 1000; //Interval of 2sec
mainTimer.AutoReset = false;
//mainTimer.Enabled = true;
mainTimer.Start();
private void main(object sender, EventArgs args)
mainTimer.Stop();
mainTimer.Dispose();
watcher = new FileSystemWatcher
Path = @"C:\Users\user\Desktop\newData",
NotifyFilter = NotifyFilters.LastWrite,
;
watcher.Created += FileSystemWatcher_Changed;
watcher.Renamed += FileSystemWatcher_Renamed;
watcher.Changed += FileSystemWatcher_Changed;
watcher.EnableRaisingEvents = true;
public static void FileSystemWatcher_Changed(object source, FileSystemEventArgs e)
string path = e.FullPath;
DataTable imported_data = GetDataFromFile(path);
if (imported_data == null) return;
SaveImportDataToDatabase(imported_data);
private static DataTable GetDataFromFile(string path)
DataTable importedData = new DataTable();
try
using (StreamReader sr = new StreamReader(path))
string[] headerColumns = header.Split(';');
foreach (string headerColumn in headerColumns)
importedData.Columns.Add(headerColumn);
string[] headerColumns = "misura_durezza";
foreach (string headerColumn in headerColumns)
importedData.Columns.Add(headerColumn);
while (!sr.EndOfStream)
string line = sr.ReadLine();
if (string.IsNullOrEmpty(line))
MessageBox.Show("no file data");
return null;
DataRow importedRow = importedData.NewRow();
importedRow[0] = line.ToString();
importedData.Rows.Add(importedRow);
catch (Exception e)
Console.WriteLine("the file could not be read:");
Console.WriteLine(e.Message);
return importedData;
private static void SaveImportDataToDatabase(DataTable imported_data)
using (mysqlConnection conn = new MySqlConnection("Server=localhost;Database=controlmachine;Uid=root;Pwd="))
try
WriteToFile($"Connection to database");
conn.Open();
WriteToFile($"Connected to database");
foreach (DataRow importRow in imported_data.Rows)
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "INSERT INTO temp_d1 (misura_durezza) VALUES (@misura_durezza)";
WriteToFile($"Creating query");
cmd.Parameters.AddWithValue("@misura_durezza", importRow["misura_durezza"]);
WriteToFile($"Executing query");
cmd.ExecuteNonQuery();
catch
WriteToFile($"Failed to insert into the database");
public static void FileSystemWatcher_Renamed(object source, RenamedEventArgs e)
WriteToFile($"File Renamed: e.OldFullPath renamed to e.FullPath");
private void OnElapsedTime(object source, ElapsedEventArgs e)
WriteToFile("Service is recalled at " + DateTime.Now);
protected override void OnStop()
WriteToFile("Service is stopped at " + DateTime.Now);
public static void WriteToFile(string Message)
string path = "C:\\Users\\user\\Desktop\\serviceLog";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
string filepath = "C:\\Users\\user\\Desktop\\serviceLog\\serviceLog_D1_" + DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";
if (!File.Exists(filepath))
// Create a file to write to.
using (StreamWriter sw = File.CreateText(filepath))
sw.WriteLine(Message);
else
using (StreamWriter sw = File.AppendText(filepath))
sw.WriteLine(Message);
【问题讨论】:
无关:考虑使用日志框架。它会让您的生活更轻松。 计时器为什么这么麻烦? 另外,磁盘 I/O 和数据库 I/O 是昂贵的操作。您不想在事件处理程序中执行它们。我会创建一个阻塞队列并在其上放置一个线程块,等待输入。然后,我只需将来自事件处理程序的文件路径排入队列,并让专用线程执行文件 I/O 和 DB I/O。 也许或者我会考虑DataFlow。但这似乎很简单。importedRow[0] = line.ToString();
- line
已经是一个字符串。
很可能是您的 WriteToFile 方法失败了。它不受 try / catch 的保护,并且可以被不同的线程调用。因此,虽然线程 1 刚刚打开了 Append 的日志文件,但线程 2 也试图做同样的事情。执行日志框架或尝试使该方法线程安全。
【参考方案1】:
你有一个错误,你订阅了同一个事件两次。
watcher.Created += FileSystemWatcher_Changed;
【讨论】:
即使我删除了这一行,观察者继续在数据库中插入服务启动后创建的第一个文件【参考方案2】:NotifyFilters.LastWrite 赶上两个事件。
我改了
watcher = new FileSystemWatcher
Path = @"C:\Users\user\Desktop\newData",
NotifyFilter = NotifyFilters.FileName,
;
现在可以了
【讨论】:
以上是关于C# FileSystemWatcher - 多个事件的主要内容,如果未能解决你的问题,请参考以下文章
C#(098):文件监视 FileSystemWatcher