Streamreader锁定文件

时间:2012-02-22 05:29:02

标签: c# file locking streamreader

我有一个c#app(Windows服务),它会触发一个读取目录中文件的计时器事件,并使用文件中的数据发送短信。当事件触发时,它会在处理新文件之前尝试将“已处理”目录中的已处理文件移动到“已完成”目录。我不断得到“另一个进程正在使用的文件”异常,虽然我很确定我处理了使用这些文件的所有内容。如果我停止服务并再次启动它,则会释放文件。有什么想法吗?

//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);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:7)

  

有什么想法吗?

您正在以完全不同的流程运行病毒检查程序。它正在检测文件是否已更改并暂时锁定它以检查它以查看您刚刚对该文件执行的编辑是否引入了病毒。它会在几毫秒内解锁。

禁用病毒检查程序是一个坏主意。相反,你只需要忍受它;编写代码,以便在有大量进程争夺文件锁定的世界中保持健壮。

答案 1 :(得分:1)

StreamReader smsmessage = new StreamReader(filePath);

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

您正在初始化smsmessage两次,但只处理其中一个实例。第一行构造一个StreamReader,然后用filenameinfo.OpenText()创建的实例覆盖对该实例的引用。这会留下一个不再有任何引用但没有被处置的实例。该实例可能正在锁定文件,并且您无法保证何时将其处置。即使它没有锁定,你仍然应该解决这个问题。