【问题标题】:Monitoring text file for changed contents prevents the file from being written监视更改内容的文本文件可防止文件被写入
【发布时间】:2015-11-05 05:50:02
【问题描述】:

我有一个文本文件,并且正在将文件中的值读入应用程序(控制台应用程序)。当文本文件中的值发生更改时,我想更新应用程序中的值。我参考了这个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"));
            }
        }
    }

【问题讨论】:

  • 不确定循环是否导致了这个问题。你能利用FileSystemWatcher
  • 嗨@qxg,感谢您的评论。在实际环境中,文本文件中的值将是配置应用程序中的值(连接到配置服务器),我可以从配置应用程序中检索值,但无法更新我的应用程序中的值一旦值改变。对于上面的问题,我只是举了一个与实际类似的简单例子。
  • 您的代码对我有用。检查其他问题。
  • 运行我的应用程序后,值一直在循环,当我更改文本文件中的值时,它不允许我保存,因为该文件已被另一个程序使用。
  • 那只是文件系统的问题?所以问题不在于如何实现INotifyPropertyChanged(当然,最好通过比较TestValue 属性中的旧值来检查值是否真的改变了)。您对如何从另一个应用程序/服务器读取值有疑问。如果可能,请更新问题。

标签: c# console-application updates inotifypropertychanged


【解决方案1】:

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

  1. 您在读取文件时会不停地轮询,这将给任何其他进程写入文件留下很少的时间(基本上没有时间)。
  2. 无论何时调用属性设置器,您都会引发 PropertyChanged 事件,无论属性值是否确实发生了变化。
  3. 您在关闭文件之前引发了PropertyChanged 事件。这不必要地延长了文件保持打开的时间(实际上,它会导致事件处理程序强制文件保持打开任意长时间的风险)。

上述最简单的修复方法如下所示:

        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 及时更新,从而导致延迟(根据我的经验,最多几十秒)收到更改通知。

如果您最多可以接受,例如在收到通知之前延迟一分钟,那么我推荐FileSystemWatcher。否则,只需每秒轮询一次(或更不频繁),或者您至少检查修改时间戳的 #1 选项就可以了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    相关资源
    最近更新 更多