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# FileSystemWatcher - 多个事件

c# 中的FileSystemWatcher问题

C#(098):文件监视 FileSystemWatcher

C#的FileSystemWatcher用法实例详解

C# 之 FileSystemWatcher事件多次触发的解决方法

C# 中的 FileStream 和 FileSystemWatcher,奇怪的问题“进程无法访问文件”