2015-11-05 63 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選項就可以。