NET问答: 如何实现读写 file 的时候不用锁模式?

咨询区

  • Homam

我先说一下我的顾虑,是这样的,我有一个 windows service 服务在不断的写入日志,同时我还有个看板程序在不断的获取 windows service 程序写入的日志。

问题是:service 程序在写日志的时候会 lock 文件,看板程序在读取的时候也会 lock 文件,这就很尴尬了,经常遇到进程被占用的异常。.

服务程序代码:

void WriteInLog(string logFilePath, data)
{
    File.AppendAllText(logFilePath, string.Format("{0} : {1}\r\n", DateTime.Now, data));
}

看板程序代码:

        int index = 0;
        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                using (StreamReader sr = new StreamReader(logFilePath))
                {
                    while (sr.Peek() >= 0)  // reading the old data
                    {
                        AddLineToGrid(sr.ReadLine());
                        index++;
                    }
                    sr.Close();
                }

                timer1.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        private void timer1_Tick(object sender, EventArgs e)
        {
            using (StreamReader sr = new StreamReader(logFilePath))
            {
                // skipping the old data, it has read in the Form1_Load event handler
                for (int i = 0; i < index ; i++) 
                    sr.ReadLine();

                while (sr.Peek() >= 0) // reading the live data if exists
                {
                    string str = sr.ReadLine();
                    if (str != null)
                    {
                        AddLineToGrid(str);
                        index++;
                    }
                }
                sr.Close();
            }
        }

请问大家我该如何解决此问题?

回答区

  • Manfred

你的问题在于写入和读取都是以排他的方式进行,其实 FileStream 中是可以支持共享的方式进行读写的。

比如将 service 代码改造如下:

var outStream = new FileStream(logfileName, FileMode.Open, 
                               FileAccess.Write, FileShare.ReadWrite);

看板程序改造如下:

var inStream = new FileStream(logfileName, FileMode.Open, 
                              FileAccess.Read, FileShare.ReadWrite);

用完的时候记得 Close 一下,对了, FileStream 实现了 IDisposable 接口,可以用 using 包一下,参考如下代码:

using(var outStream = ...)
{
   // using outStream here
   ...
}

点评区

我特意看了下 FileStream 的 FileShare.ReadWrite 参数解释。

    [ComVisible(true)]
    [Flags]
    public enum FileShare
    {
        None = 0,
        Read = 1,
        Write = 2,
        //
        // Summary:
        //     Allows subsequent opening of the file for reading or writing. If this flag is
        //     not specified, any request to open the file for reading or writing (by this process
        //     or another process) will fail until the file is closed. However, even if this
        //     flag is specified, additional permissions might still be needed to access the
        //     file.
        ReadWrite = 3,
        Delete = 4,
        Inheritable = 16
    }

我去,原来还可以这样玩,对 FileStream 用的还不透彻,学习了。