流读取器锁定文件

本文关键字:文件 锁定 读取 | 更新日期: 2023-09-27 18:25:27

我有一个c#应用程序(Windows服务),它会触发一个计时器事件,读取目录中的文件并使用文件中的数据发送SMS。下次触发事件时,它会尝试在处理新文件之前,将"processed"目录中已处理的文件移动到"Completed"目录。我不断收到一个"另一个进程正在使用的文件"异常,尽管我很确定我已经处理掉了所有使用这些文件的东西。如果我停止服务并重新启动它,文件就会被释放。有什么想法吗?

//Code that fires the timer    
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
namespace SmsWindowsService
{
    public partial class SmsWindowsService : ServiceBase
    {
        private static System.Timers.Timer aTimer;
        public SmsWindowsService()
        {
            InitializeComponent();
            if (!System.Diagnostics.EventLog.SourceExists("MatterCentreSMSSource"))
            {
                System.Diagnostics.EventLog.CreateEventSource(
                    "MatterCentreSMSSource", "MatterCentreSMSLog");
            }
            elMatterCentreSMS.Source = "MatterCentreSMSSource";
            elMatterCentreSMS.Log = "MatterCentreSMSLog";
        }
        protected override void OnStart(string[] args)
        {
            string logText = string.Empty;
            logText = "MatterCentreSMS Service started successfully on " + DateTime.Now;
            WriteEventLog(logText);
            //Create a timer with a ten second interval.
            aTimer = new System.Timers.Timer(10000);
            //Hook up the Elapsed event for the timer.
            aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            //Set the Interval to 5 minutes.
            //aTimer.Interval = 300000;
            aTimer.Interval = 60000;
            aTimer.Enabled = true;
            // If the timer is declared in a long-running method, use
            // KeepAlive to prevent garbage collection from occurring
            // before the method ends.
            //GC.KeepAlive(aTimer);
            GC.Collect();
        }
        protected override void OnStop()
        {
            string logText = string.Empty;
            logText = "MatterCentreSMS Service stopped on " + DateTime.Now;
            WriteEventLog(logText);
        }
        private void WriteEventLog(string logText)
        {
            elMatterCentreSMS.WriteEntry(logText);
        }
        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            string ex = string.Empty;
            SendSms s = new SendSms();
            ex = s.ProcessSms();
            if (ex.Length > 1)
                WriteEventLog(ex);
            //ex = RestartService("SmsWindowsService", 60000);
            //WriteEventLog(ex);
        }
        public string RestartService(string serviceName, int timeoutMilliseconds)
        {
            ServiceController service = new ServiceController(serviceName);
            try
            {
                int millisec1 = Environment.TickCount;
                TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
                service.Stop();
                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
                // count the rest of the timeout
                int millisec2 = Environment.TickCount;
                timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds - (millisec2 - millisec1));
                service.Start();
                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
                return "MatterCentreSMS Service successfully restarted on " + DateTime.Now;
            }
            catch (Exception e)
            {
                return Convert.ToString(e);
            }
        }
    }
}
//Code that reads the file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
namespace SmsWindowsService
{
    class Message
    {
        private string filePath;
        public Message(string filePath)
        {
            this.filePath = filePath;
        }
        public string readSMS(string filePath)
        {
            const string searchmessage = "[B-->]";
            StreamReader smsmessage = new StreamReader(filePath);
            try
            {
                FileInfo filenameinfo = new FileInfo(filePath);
                if (filenameinfo.Exists == false)
                    throw new SMSReaderException(String.Format("SMS Message {0} cannot be found ...", filePath), filePath);
                smsmessage = filenameinfo.OpenText();
                string smsoutput = smsmessage.ReadToEnd();
                int endpos = smsoutput.IndexOf(searchmessage);
                smsoutput = smsoutput.Substring(endpos + searchmessage.Length);
                smsoutput = smsoutput.Replace("&", "&");
                smsoutput = smsoutput.Replace("'"", """);
                smsoutput = smsoutput.Replace("'", "'");
                filenameinfo = null;
                smsmessage.Close();
                smsmessage.Dispose();
                return smsoutput;
            }
            catch(Exception e)
            {
                throw new Exception("Help", e.InnerException);
            }
            finally
            {
                smsmessage.Close();
                smsmessage.Dispose();
            }
        }
    }
    public class SMSReaderException : System.IO.FileNotFoundException
    {
        public SMSReaderException(string message, string filename)
            : base(message, filename)
        {
        }
    }
    }
//Code that connects to web service and send sms
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Net;
using System.Configuration;
using SmsWindowsService.EsendexSendSmsService;
namespace SmsWindowsService
{
    class SendSms
    {
        string filePath = string.Empty;
        string directoryPath = string.Empty;
        string directoryPathProcessing = string.Empty;
        string directoryPathCompleted = string.Empty;
        string smsLogfileDirectory = string.Empty;
        string smsLogfilePath = string.Empty;
        string mattercentreSMS = string.Empty;
        string messageBody = string.Empty;
        string messageId = string.Empty;
        string messageStatus = string.Empty;
        string dateTodayString = string.Empty;
        long mobileNumber;
        EsendexSendSmsService.SendService send;
        public SendSms()
        {
            directoryPath = ConfigurationSettings.AppSettings[@"directoryPath"];
            directoryPathProcessing = ConfigurationSettings.AppSettings[@"directoryPathProcessing"];
            directoryPathCompleted = ConfigurationSettings.AppSettings[@"directoryPathCompleted"];
            smsLogfileDirectory = ConfigurationSettings.AppSettings[@"smsLogfileDirectory"];            
            dateTodayString = DateTime.Now.ToString("yyyy/MM/dd");
            smsLogfilePath = smsLogfileDirectory + dateTodayString.Replace(@"/", "_") + ".txt";
            send = new EsendexSendSmsService.SendService();
        }
        public string ProcessSms()
        {
            string ex = string.Empty;
            try
            {
                DirectoryInfo di = new DirectoryInfo(directoryPathProcessing);
                ex = MoveFilesToCompleted(directoryPathProcessing, directoryPathCompleted);
                if (ex.Length > 1)
                    return ex;
                ex = MoveFilesToProcessing(directoryPath, directoryPathProcessing);
                if (ex.Length > 1)
                    return ex;
                FileInfo[] subFilesProcessing = di.GetFiles();
                foreach (FileInfo subFile in subFilesProcessing)
                {
                    filePath = directoryPathProcessing + subFile.Name;
                    Message sms = new Message(filePath);
                    mattercentreSMS = sms.readSMS(filePath);
                    MessageDetails d = new MessageDetails(mattercentreSMS);
                    mobileNumber = d.GetMobileNumber();
                    messageBody = d.GetMessageBody();
                    ex = SetHeader();
                    if (ex.Length > 1)
                        return ex;
                    ex = SetProxy();
                    if (ex.Length > 1)
                        return ex;
                    //Send the message and get the returned messageID and send status
                    messageId = send.SendMessage(Convert.ToString(mobileNumber), messageBody, EsendexSendSmsService.MessageType.Text);
                    messageStatus = Convert.ToString(send.GetMessageStatus(messageId));
                    ex = WriteLogFile(messageId, subFile.Name, messageStatus);
                    if (ex.Length > 1)
                        return ex;
                    send.Dispose();
                }
                di = null;
                subFilesProcessing = null;
                return ex;
            }
            catch (Exception e)
            {
                return Convert.ToString(e);
            }
        }
        private string MoveFilesToCompleted(string directoryPathProcessing, string directoryPathCompleted)
        {
            DirectoryInfo din = new DirectoryInfo(directoryPathProcessing);
            try
            {                
                FileInfo[] subFiles = din.GetFiles();
                foreach (FileInfo subFile in subFiles)
                {
                    subFile.MoveTo(directoryPathCompleted + subFile.Name);
                }
                subFiles = null;
                return "";                
            }
            catch (Exception e)
            {
                return Convert.ToString(e);
            }
            finally
            {
                din = null;
            }
        }
        private string MoveFilesToProcessing(string directoryPath, string directoryPathProcessing)
        {
            DirectoryInfo din = new DirectoryInfo(directoryPath);
            try
            {
                FileInfo[] subFiles = din.GetFiles();
                foreach (FileInfo subFile in subFiles)
                {
                    subFile.MoveTo(directoryPathProcessing + subFile.Name);
                }
                subFiles = null;
                return "";
            }
            catch (Exception e)
            {
                return Convert.ToString(e);
            }
            finally
            {
                din = null;
            }
        }
        private string SetHeader()
        {
            try
            {
                //Setup account details in the header
                EsendexSendSmsService.MessengerHeader header = new EsendexSendSmsService.MessengerHeader();
                header.Account = ConfigurationSettings.AppSettings[@"smsServiceUrl"];
                header.Username = ConfigurationSettings.AppSettings[@"smsServiceUsername"];
                header.Password = ConfigurationSettings.AppSettings[@"smsServicePassword"];
                // set the SOAP header Authentication values
                send.MessengerHeaderValue = header;
                return "";
            }
            catch (Exception e)
            {
                return Convert.ToString(e);
            }
        }
        private string SetProxy()
        {
            try
            {
                //Create a web proxy object as the proxy server block direct request to esendex 
                WebProxy myProxy = new WebProxy(ConfigurationSettings.AppSettings[@"proxyaddress"], true);
                myProxy.Credentials = new NetworkCredential(ConfigurationSettings.AppSettings[@"username"], ConfigurationSettings.AppSettings[@"password"]);
                WebRequest.DefaultWebProxy = myProxy;
                send.Proxy = myProxy;
                return "";
            }
            catch (Exception e)
            {
                return Convert.ToString(e);
            }
        }
        private string WriteLogFile(string messageId, string smsFileName, string messageStatus)
        {
            try
            {
                if (File.Exists(smsLogfilePath))
                {
                    //file is not empty - append log entry to file
                    using (StreamWriter writeSmsLog = File.AppendText(smsLogfilePath))
                    {
                        writeSmsLog.WriteLine(messageId + "             " + smsFileName + "    " + DateTime.Now + "     " + messageStatus);
                        writeSmsLog.Close();
                    }
                }
                else
                {
                    FileStream fs = File.OpenWrite(smsLogfilePath);
                    fs.Flush();
                    fs.Close();
                    fs.Dispose();
                    using (StreamWriter writeSmsLog = new StreamWriter(smsLogfilePath, true))
                    {
                        writeSmsLog.WriteLine("Message_ID                                       File_Name                                    Date_Sent                  Status");
                        writeSmsLog.WriteLine("======================================================================================================================================");
                        writeSmsLog.WriteLine(messageId + "             " + smsFileName + "    " + DateTime.Now + "     " + messageStatus);
                        writeSmsLog.Close();
                    }
                }
                return "";
            }
            catch (Exception e)
            {
                return Convert.ToString(e);
            }
        }
    }
}

流读取器锁定文件

有什么想法吗?

你在一个完全不同的过程中运行病毒检查器。它检测到文件已更改,并暂时锁定它,以便检查您刚刚对文件执行的编辑是否引入了病毒。它会在几毫秒内解锁。

禁用病毒检查器是个坏主意。相反,你将不得不接受它;在一个有很多进程争夺文件锁的世界里,编写代码要健壮。

StreamReader smsmessage = new StreamReader(filePath);
try
{
    FileInfo filenameinfo = new FileInfo(filePath);
    ....
    smsmessage = filenameinfo.OpenText();
    ...

您正在初始化smsmmesage两次,但只处理其中一个实例。第一行构造一个StreamReader,然后用filenameinfo创建的实例覆盖对该实例的引用。OpenText()。这会给您留下一个实例,该实例不再具有任何引用,也没有被释放。该实例可能持有该文件的锁,并且您无法保证它何时会被释放。即使它没有锁,你仍然应该修复它。