2015-11-05 65 views
1

我有一个文本文件,文件中的值正在读入应用程序(控制台应用程序)。我想在文本文件中的值更改时更新应用程序中的值。我已经提到了这个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")); 
      } 
     } 
    } 
+0

不确定循环是否导致此问题。你可以利用[FileSystemWatcher](https://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher%28v=vs.110%29.aspx) – qxg

+0

嗨@qxg,感谢您的评论。在实际环境中,文本文件中的值将是配置应用程序(连接到配置服务器)中的值,我可以从配置应用程序中检索值,但无法更新我的应用程序中的值一旦价值改变了。对于上面的问题,我只是举了一个类似于实际的简单例子。 – YWah

+0

你的代码适合我。检查其他问题。 – qxg

回答

0

有至少三个严重问题是在你的代码:

  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选项就可以。