C# 文件监视程序问题

C# 文件监视程序问题,c#,file-watcher,C#,File Watcher,好的,所以这次我创建了一个服务,其中包含一个文件观察程序,用于在创建文件后处理该文件 当正在处理的文件达到1000个时,我的服务似乎崩溃了,因为我收到了大量的消息 以下是我的逻辑:文件进入,文件观察者阅读文本,将其发送到电子邮件,插入数据库,将原始邮件移动到文件夹 在服务启动时,我先处理挂起的消息,然后再开始观看。我说的是1000多个文本文件挂起,我的服务需要大约一秒钟来处理每个文件 一切正常,但当传入的文件总数达到1000个时,它就会崩溃。 有时,服务停止处理挂起的文件,只开始查找新文件 我的

好的,所以这次我创建了一个服务,其中包含一个文件观察程序,用于在创建文件后处理该文件

当正在处理的文件达到1000个时,我的服务似乎崩溃了,因为我收到了大量的消息

以下是我的逻辑:文件进入,文件观察者阅读文本,将其发送到电子邮件,插入数据库,将原始邮件移动到文件夹

在服务启动时,我先处理挂起的消息,然后再开始观看。我说的是1000多个文本文件挂起,我的服务需要大约一秒钟来处理每个文件

一切正常,但当传入的文件总数达到1000个时,它就会崩溃。 有时,服务停止处理挂起的文件,只开始查找新文件

我的InternalBufferSize=64000是建议的最大值

请帮助我编写代码我知道它应该是多线程的,以便更好地处理,但我不是专家:

 protected override void OnStart(string[] args)
    {
        using(TREEEntities TEX = new TREEEntities())
        {
         var mp= TEX.TREE_settings.FirstOrDefault(x=>x.SET_key =="MSGDump");
         MsgsPath = mp.SET_value;
         var dc = TEX.TREE_settings.FirstOrDefault(x => x.SET_key == "DupCash");
         DupCash = Convert.ToInt16(dc.SET_value);
        }
        if (Directory.Exists(MsgsPath))
        {
            if (!Directory.Exists(MsgsPath+"\\Archive"))
            {
                Directory.CreateDirectory(MsgsPath+"\\Archive");
            }
            if (!Directory.Exists(MsgsPath + "\\Duplicates"))
            {
                Directory.CreateDirectory(MsgsPath + "\\Duplicates");
            }
            if (!Directory.Exists(MsgsPath + "\\Unsent"))
            {
                Directory.CreateDirectory(MsgsPath + "\\Unsent");
            }
        }
        else
        {
            Directory.CreateDirectory(MsgsPath);
            Directory.CreateDirectory(MsgsPath + "\\Archive");
            Directory.CreateDirectory(MsgsPath + "\\Duplicates");
            Directory.CreateDirectory(MsgsPath + "\\Unsent");
        }         

        processPending();//<--- process pending files after last service stop
        fileSystemWatcher1.Path = MsgsPath;//<--- path to be watched  
        fileSystemWatcher1.EnableRaisingEvents = true;
        fileSystemWatcher1.InternalBufferSize = 64000;
        addToLog(DateTime.Now, "Service Started", 0, "Service", "Info");
        addToLog(DateTime.Now, "File Watcher Started", 0, "Service", "Info");
        //dupList.Clear();//<--- clear duplicates validation list
    }

    protected override void OnStop()
    {
        fileSystemWatcher1.EnableRaisingEvents = false;
        addToLog(DateTime.Now, "File Watcher Stopped", 0, "Service", "Alert");
        addToLog(DateTime.Now, "Service Stopped", 0, "Service", "Alert");
    }



    private void fileSystemWatcher1_Created(object sender, FileSystemEventArgs e)
    {             
        try
        {
            //---------read from file------------
            Thread.Sleep(200);//<---give the file some time to get released
            string block;
            using (StreamReader sr = File.OpenText(MsgsPath + "\\" + e.Name))
            {
                block = sr.ReadToEnd();
            }
            PRT = block.Substring(block.Length - 6, 6);//<--- get the printer name
            seq = Convert.ToInt16(block.Substring(block.Length - 20, 20).Substring(0, 4));//<--- get the sequence number
            switch (PRT)//<----track sequence number from the 3 printers
            {
                case "64261B"://<---prt1
                    int seqPlus1=0;
                    if(seqPrt1 == 9999)//<---ignore sequence change from 9999 to 1
                    { seqPlus1 = 1; }
                    else { seqPlus1 = seqPrt1 + 1; }                         
                    if (seq != seqPlus1 && seqPrt1 != 0)//<---"0" to avoid first service start
                    {
                        int x = seq - seqPrt1 - 1;
                        for (int i = 1; i <= x; i++)
                        {
                            addToMissing(PRT, seqPlus1);
                            addToLog(DateTime.Now, "Missing Sequence Number On Printer: " + PRT + " - " + seqPlus1, seqPlus1, "Service", "Missing");
                            seqPlus1++;
                        }                           
                        seqPrt1 = seq;
                    }
                    else { seqPrt1 = seq; }
                    break;
                case "24E9AA"://<---prt2
                    int seqPlus2=0;
                    if(seqPrt2 == 9999)
                    { seqPlus2 = 1; }
                    if (seq != seqPlus2 && seqPrt2 != 0)
                    {
                        int x = seq - seqPrt2 - 1;
                        for (int i = 1; i <= x; i++)
                        {
                            addToMissing(PRT, seqPlus2);
                            addToLog(DateTime.Now, "Missing Sequence Number On Printer: " + PRT + " - " + seqPlus2, seqPlus2, "Service", "Missing");
                            seqPlus2++;
                        }                          
                        seqPrt2 = seq;
                    }
                    else { seqPrt2 = seq; }
                    break;
                case "642602"://<---prt3
                    int seqPlus3=0;
                    if(seqPrt3 == 9999)
                    { seqPlus3 = 1; }
                    if (seq != seqPlus3 && seqPrt3 != 0)
                    {
                        int x = seq - seqPrt3 - 1;
                        for (int i = 1; i <= x; i++)
                        {
                            addToMissing(PRT, seqPlus3);
                            addToLog(DateTime.Now, "Missing Sequence Number On Printer: " + PRT + " - " + seqPlus3, seqPlus3, "Service", "Missing");
                            seqPlus3++;
                        }                      
                        seqPrt3 = seq;
                    }
                    else { seqPrt3 = seq; }
                    break;
            }
            block = block.Remove(block.Length - 52);//<--- trim the sequence number and unwanted info
            string[] Alladd;
            List<string> sent = new List<string>();
            if (!dupList.Contains(block)) //<--- if msg not found in duplicates validation list
            {
                //--------extract values--------------
                if (block.Substring(0, 3) == "\r\nQ") //<--- if the msg. contains a priority code
                {
                    Alladd = block.Substring(0, block.IndexOf(".")).Replace("\r\n", " ").Substring(4).Split(' ').Distinct().Where(x => !string.IsNullOrEmpty(x)).ToArray(); ;
                }
                else//<--- if no priority code
                {
                    Alladd = block.Substring(0, block.IndexOf(".")).Replace("\r\n", " ").Substring(1).Split(' ').Distinct().Where(x => !string.IsNullOrEmpty(x)).ToArray(); ;
                }
                string From = block.Substring(block.IndexOf('.') + 1).Substring(0, 7);
                string Msg = block.Substring(block.IndexOf('.') + 1);
                Msg = Msg.Substring(Msg.IndexOf('\n') + 1);

                //--------add msg content to the DB group table--------
                using (TREEEntities TE1 = new TREEEntities())
                {
                    TREE_group tg = new TREE_group()
                    {
                        GROUP_original = block,
                        GROUP_sent = Msg,
                        GROUP_dateTime = DateTime.Now,
                        GROUP_from = From,
                        GROUP_seq = seq,
                        GROUP_prt = PRT,
                    };
                    TE1.AddToTREE_group(tg);
                    TE1.SaveChanges();
                    GID = tg.GROUP_ID;
                }
                //--------validate addresses---------------
                foreach (string TB in Alladd)
                {
                    string email = "";
                    string typeB = "";
                    TREEEntities TE = new TREEEntities();
                    var q1 = from x in TE.TREE_users where x.USR_TypeB == TB && x.USR_flag == "act" select new { x.USR_email, x.USR_TypeB };
                    foreach (var itm in q1)
                    {
                        email = itm.USR_email;
                        typeB = itm.USR_TypeB;
                    }

                    //-------send mail if the user exist----                  
                    if (TB == typeB)
                    {
                        if (typeB == "BAHMVGF")
                        {
                            addToFtl(block);
                        }
                        try
                        {
                            sendMail SM = new sendMail();
                            SM.SendMail(Msg, "Message from: " + From, email);
                            //---save record in DB----
                            addToMsg(typeB, email,"sent","act",1,GID,seq);                               
                            sent.Add(typeB);
                        }
                        catch (Exception x)
                        {
                            addToMsg(typeB, email, "Failed", "act", 1, GID, seq);                              
                            addToLog(DateTime.Now, "Send message failed: " + x.Message, GID, "Service", "Warning");
                        }
                    }
                    //-------if no user exist----
                    else
                    {
                        if (TB == "BAHMVGF")
                        {
                            addToFtl(block);
                        }
                        addToMsg(TB, "No email", "Failed", "act", 1, GID, seq);                          
                        addToLog(DateTime.Now, "Send message failed, unknown Type-B address: " + TB, GID, "Service", "Warning");
                    }
                }

                if (sent.Count < Alladd.Count())//<--- if there is unsent addresses
                {
                    StringBuilder b = new StringBuilder(block);
                    foreach (string add in sent)
                    {
                        b.Replace(add, "");//<--- remove address that has been sent from the original message and write new msg. to unsent folder
                    }
                    if (!Directory.Exists(MsgsPath + "\\Unsent"))
                    {
                        Directory.CreateDirectory(MsgsPath + "\\Unsent");
                    }
                    using (StreamWriter w = File.AppendText(MsgsPath + "\\Unsent\\" + e.Name))
                    {
                        w.WriteLine(b);
                    }
                }
                sent.Clear();
                //---add to dupList to validate the next messages-------------
                if (dupList.Count > DupCash)
                {
                    dupList.RemoveAt(0);
                }
                dupList.Add(block);
                //---move msg to archive folder-----------------     
                if (!Directory.Exists(MsgsPath + "\\Archive"))
                {
                    Directory.CreateDirectory(MsgsPath + "\\Archive");
                }
                File.Move(MsgsPath + "\\" + e.Name, MsgsPath + "\\Archive\\" + e.Name);
            }

            else //<--- if message is a duplicate
            {
                addToLog(DateTime.Now, "Duplicated message, message not sent", seq, "Service", "Info");
                //---move msg to duplicates folder-----------------  
                if (!Directory.Exists(MsgsPath + "\\Duplicates"))
                {
                    Directory.CreateDirectory(MsgsPath + "\\Duplicates");
                }
                File.Move(MsgsPath + "\\" + e.Name, MsgsPath + "\\Duplicates\\" + e.Name);
            }

        }
        catch (Exception x)
        {
            addToLog(DateTime.Now, "Error: " + x.Message, seq, "Service", "Alert");
            if (!Directory.Exists(MsgsPath + "\\Unsent"))
            {
                Directory.CreateDirectory(MsgsPath + "\\Unsent");
            }
            //---move msg to Unsent folder-----------------                    
            File.Move(MsgsPath + "\\" + e.Name, MsgsPath + "\\Unsent\\" + e.Name);
        }

    }

我想添加这个作为一个评论,但它超过了允许的字符数,所以这里开始

我在代码中注意到的第一件事是,您正在创建的事件处理程序中执行所有文件处理。这不是一个好的做法,您应该始终让您的FileSystemWatcher事件处理程序执行最少的工作,因为它可能会导致溢出,这可能是您所面临的问题。 相反,最好将工作委托给单独的线程。您可以将事件添加到队列中,让后台线程来处理它们。您可以过滤事件处理程序中的文件,这样队列就不会被垃圾填满

在事件处理程序中使用睡眠也被认为是一种不好的做法,因为这样会阻止FileSystemWatcher事件

允许的最大缓冲区大小为64K,除非您处理的是长路径,否则这不是建议的缓冲区大小。增加缓冲区的大小是昂贵的,因为它来自无法交换到磁盘的非分页内存,所以请尽可能保持缓冲区的小。要避免缓冲区溢出,请使用和属性过滤掉不需要的更改通知


最后,我建议在尝试编写代码之前,先阅读FileSystemWatcher并在线查看几个示例,因为Windows watcher有些脆弱,而且容易出错

增加缓冲区大小会有帮助吗?我的所有文件都在本地专用服务器上,不在共享网络上。如果您需要帮助,并且认为这不是以前引用的问答的副本,您需要更具体一些,而不仅仅是它崩溃。我在事件查看器中看到了这一点:windows服务意外终止。您可以拆分为多个注释。@tbodt不必是个聪明人,答案是正确的。我建议您也阅读MSDN文章。