监视文本文件以查找已更改的内容可防止写入文件

时间:2015-11-05 05:50:03

标签: c# console-application updates inotifypropertychanged

我有一个文本文件,文件中的值正被读入应用程序(控制台应用程序)。我想更改文本文件中的值时更新应用程序中的值。我已经提到了这个link并做了一些修改。结果是当我更改文本文件中的值并尝试保存它时,应用程序中的值不会更新,因为无法保存文件。

如果更改文本文件中的值,如何更新应用程序中的值?

class Program
    {
        static void Main(string[] args)
        {
            TestClass sample = new TestClass();
            sample.PropertyChanged += new PropertyChangedEventHandler(sample_PropertyChanged);

            while (true)
            {
                using (StreamReader sr = new StreamReader("Testing.txt"))
                {
                    // Read the stream to a string, and write the string to the console.
                    string str = sr.ReadToEnd();
                    sample.TestValue = str;
                }  
            }
        }

        static void sample_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            TestClass sample = (TestClass)sender;
            /*
             * Use expression behind if you have more the one property instead sample.TestValue
             * typeof(TestClass).GetProperty(e.PropertyName).GetValue(sample, null)*/
            Console.WriteLine("Value of property {0} was changed! New value is {1}", e.PropertyName, sample.TestValue);
        }
    }

    public class TestClass : INotifyPropertyChanged
    {

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        string testValue = string.Empty;
        public string TestValue
        {
            get { return testValue; }
            set
            {
                testValue = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("TestValue"));
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

您的代码中至少存在三个严重问题:

  1. 您在阅读文件时不断轮询,这将为任何其他进程写入文件留下很少的时间(基本上没有)。
  2. 在调用属性设置器时,无论属性值是否实际发生更改,都会引发PropertyChanged事件。
  3. 在关闭文件之前,您正在提升PropertyChanged事件。这不必要地延长了文件保持打开的时间段(实际上,它会使事件处理程序可以强制文件在任意长时间内保持打开状态)。
  4. 上述最简单的修复方法如下所示:

            while (true)
            {
                string str = File.ReadAllText("Testing.txt");
    
                sample.TestValue = str;
                Thread.Sleep(1000); // sleep for 1 second
            }
    

    和此:

        public string TestValue
        {
            get { return testValue; }
            set
            {
                if (testValue != value)
                {
                    testValue = value;
    
                    // BUGBUG: Warning! This code is not thread-safe; it is possible for
                    // the current thread to check `PropertyChanged` just before some other
                    // thread changes its value to null, and then to try to invoke the handler
                    // just _after_ that other thread changes its value to null. This is fine
                    // if you are sure that the event and property are both only ever accessed
                    // in one single thread. But otherwise, you need to fix this bug, by
                    // following the normal C# idiom for raising events, i.e. store the field
                    // value in a local variable, and then if it's non-null, raise the event
                    // using the local variable's value instead of the event field itself.
    
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs("TestValue"));
                }
            }
        }
    

    请注意上面代码中关于您在处理活动时可能存在的错误的评论。

    除此之外,您还可以对代码进行其他一些改进:

    1. 在实际打开文件之前,使用File.GetLastWriteTimeUtc()检查文件的文件修改时间戳,如果时间戳比上次检查时更新,则只打开文件进行读取。这样可以避免不必要地打开文件,从而减少文件锁定冲突的可能性。
    2. 更好的是,除了上述内容之外,根本不进行民意调查。让FileSystemWatcher为您完成工作,只在Changed事件被引发时才读取文件。这样做的主要缺点是FileSystemWatcher并不总是(事实上,通常不会)及时通知文件的更改。它最终将引发相应的事件,但它跟踪的目录信息本身并不总是由Windows及时更新,导致在收到更改通知时出现延迟(最多几十秒,根据我的经验)。
    3. 如果您可以接受,例如在收到通知之前会有一分钟的延迟,然后我会推荐FileSystemWatcher。否则,只需每秒(或不太频繁)轮询,或者至少检查修改时间戳的#1选项,就可以了。