Multithreading 使用FileSystemMonitoring读取app.config中的更改并实时写入app.config
我正在使用FileSystemWatcher监视app.config文件中的任何更改。同时,写入配置文件 这是我的密码: MyApplication是主项目,DataCache是MyApplication中引用的clas库Multithreading 使用FileSystemMonitoring读取app.config中的更改并实时写入app.config,multithreading,c#-4.0,app-config,filesystemwatcher,configurationsection,Multithreading,C# 4.0,App Config,Filesystemwatcher,Configurationsection,我正在使用FileSystemWatcher监视app.config文件中的任何更改。同时,写入配置文件 这是我的密码: MyApplication是主项目,DataCache是MyApplication中引用的clas库 using System; using System.Threading; using System.IO; namespace MyApplication { public class Program { public static string ro
using System;
using System.Threading;
using System.IO;
namespace MyApplication
{
public class Program
{
public static string rootFolderPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
public static string configFilePath = Path.Combine(rootFolderPath, "MyApplication.exe.config");static void Main(string[] args)
{
//First Time initializing the config file.
ConfigFileMonitor.SetConfigFileAtRuntime(configFilePath);
//Initializing the config file monitor on a separate thread.
Thread monitorThread = new Thread(ConfigFileMonitor.BeginConfigFilesMonitor);
monitorThread.Start();
WriteToConfigFile();
}
static void WriteToConfigFile()
{
Console.WriteLine(String.Format("Hello {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString));
string _firstName, _lastName = string.Empty;
do
{
Console.WriteLine("");
Console.Write("First Name : ");
_firstName = Console.ReadLine();
Console.Write("Last Name : ");
_lastName = Console.ReadLine();
if(_firstName.Length>0)
DataCache.Section1Data.FirstNameString = _firstName;
if(_lastName.Length>0)
DataCache.Section1Data.LastNameString = _lastName;
Console.WriteLine(String.Format("Hello {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString));
}
while (true);
}
}
}
using System;
using System.IO;
namespace MyApplication
{
/// <summary>
/// Monitors for any change in the app.config file
/// </summary>
public class ConfigFileMonitor
{
private static FileSystemWatcher _watcher;
private static string _configFilePath = String.Empty;
private static string _configFileName = String.Empty;
/// <summary>
/// Texts the files surveillance.
/// </summary>
public static void BeginConfigFilesMonitor()
{
try
{
string fileToMonitor = Program.configFilePath;
if (fileToMonitor.Length == 0)
Console.WriteLine("Incorrect config file specified to watch");
else
{
_configFileName = Path.GetFileName(fileToMonitor);
_configFilePath = fileToMonitor.Substring(0, fileToMonitor.IndexOf(_configFileName));
}
// Use FileWatcher to check and update only modified text files.
WatchConfigFiles(_configFilePath, _configFileName);
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
}
/// <summary>
/// Watches the files.
/// </summary>
/// <param name="targetDir">The target dir.</param>
/// <param name="filteredBy">The filtered by.</param>
static void WatchConfigFiles(string targetDir, string filteredBy)
{
try
{
_watcher = new FileSystemWatcher();
_watcher.Path = targetDir;
_watcher.Filter = filteredBy;
_watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite;
_watcher.EnableRaisingEvents = true;
_watcher.Changed += new FileSystemEventHandler(FileChanged);
_watcher.WaitForChanged(WatcherChangeTypes.Changed);
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
}
/// <summary>
/// Handles the Changed event of the File control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.IO.FileSystemEventArgs"/> instance containing the event data.</param>
protected static void FileChanged(object sender, FileSystemEventArgs e)
{
try
{
_watcher.EnableRaisingEvents = false;
string filechange = e.FullPath;
Console.WriteLine("Configuration File: " + filechange + "changed");
//Since the file is changed - We have reload the configuration settings again.
SetConfigFileAtRuntime(Path.Combine(Program.rootFolderPath, "MyApplication.exe.config"));
Console.WriteLine(String.Format("New Name : {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString));
_watcher.EnableRaisingEvents = true;
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
}
/// <summary>
/// Sets the config file at runtime.
/// </summary>
/// <param name="configFilePath"></param>
public static void SetConfigFileAtRuntime(string configFilePath)
{
string runtimeconfigfile;
try
{
if (configFilePath.Length == 0)
Console.WriteLine("Please specify a config file to read from ");
else
{
runtimeconfigfile = configFilePath;
_configFileName = Path.GetFileName(configFilePath);
_configFilePath = configFilePath.Substring(0, configFilePath.IndexOf(_configFileName));
}
// Specify config settings at runtime.
//System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
DataCache.DataConfigSection.config = System.Configuration.ConfigurationManager.OpenExeConfiguration(configFilePath);
//Similarly you can apply for other sections like SMTP/System.Net/System.Web etc..
//But you have to set the File Path for each of these
//config.AppSettings.File = runtimeconfigfile;
//This doesn't actually going to overwrite you Exe App.Config file.
//Just refreshing the content in the memory.
DataCache.DataConfigSection.config.Save(System.Configuration.ConfigurationSaveMode.Modified);
//Refreshing Config Section
//ConfigurationManager.RefreshSection("appSettings");
System.Configuration.ConfigurationManager.RefreshSection("MySectionGroup/Section1");
DataCache.Section1Data.configSection1 = null;
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
}
}
}
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="MySectionGroup">
<section name="Section1" type="DataCache.DataConfigSection, DataCache" allowLocation="false" allowDefinition="Everywhere"/>
<section name="Section2" type="DataCache.DataConfigSection, DataCache" allowLocation="false" allowDefinition="Everywhere"/>
</sectionGroup>
</configSections>
<MySectionGroup>
<Section1>
<name
firstName ="Pierce"
lastName ="Brosnan"
/>
</Section1>
</MySectionGroup>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
问题是,如果控制台输入对名称进行了任何更改,则会调用FileChanged一次,后续更改不会触发它。此外,如果手动更改配置文件,它将正常工作,直到从控制台更改为止,事件将一直触发
我不知道为什么会有这种奇怪的行为。有人能帮我吗
谢谢,
莫妮卡你的密码很复杂。我的watcher代码大约是10行 不需要将监视程序的初始化转移到另一个线程。在主线程上初始化它。监视程序监视后台线程中的文件,并在发生更改时触发事件,因此无需调用WaitForChanged()方法 我已经检查了我的工作代码,并将其与您的代码进行了比较,唯一的两个区别是: 1.我的过滤器是:NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName 2.我不调用WaitForChanged()方法 3.我已将
[PermissionSet(SecurityAction.Demand,Name=“FullTrust”)]
应用于与观察者交互的所有方法
此外,请确保您监视的文件不在某个系统目录中。。。监视程序不能很好地处理这些文件。我的头撞到墙上半天,因为我正试图看C:.上的文件。短版本是:
this.Watcher = new FileSystemWatcher();
this.Watcher.Path = this.Dir;
this.Watcher.Filter = this.File;
this.Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
this.Watcher.EnableRaisingEvents = true;
this.Watcher.Changed += this.OnFileChange;
然而,这里有一个更复杂(而且难看)的示例,取自实时源代码,其中需要一些额外的处理(除了读取文件之外)
public partial class FileModule
{
private ConcurrentDictionary<string, InputFileInfo> inputFileList = new ConcurrentDictionary<string, InputFileInfo>();
public FileModule()
{
this.InitializeInputFileWatchers();
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public void EnableOrDisableRaisingEventsForFileWatchers(bool enable)
{
foreach (var el in this.inputFileList)
{
el.Value.Watcher.EnableRaisingEvents = enable;
}
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private void InitializeInputFileWatchers()
{
for (int i = 0; i < this.InputFiles.Count; i++)
{
if (File.Exists(this.InputFiles[i]))
{
InputFileInfo info = new InputFileInfo();
info.Fullpath = ((FileModuleSettings)this.Settings).InputFiles[i];
info.Watcher.Changed += this.OnFileChange;
this.inputFileList.AddOrUpdate(info.Fullpath, info, (e, v) => { return info; });
}
}
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private void OnFileChange(object source, FileSystemEventArgs e)
{
InputFileInfo info;
if (this.inputFileList.TryGetValue(e.FullPath, out info))
{
DateTime lastWriteTime = System.IO.File.GetLastWriteTime(e.FullPath);
if (info.LastHandledChange != lastWriteTime)
{
TimeSpan span = lastWriteTime.Subtract(info.LastHandledChange);
if (span.Days == 0 && span.Hours == 0 && span.Minutes == 0 && span.Seconds == 0 && span.TotalMilliseconds < this.MinimumFileChangePeriod)
{
// Event ignored due to required minimum file change period;
}
else
{
info.LastHandledChange = lastWriteTime;
this.inputFileList.AddOrUpdate(e.FullPath, info, (a, v) => { return info; });
lock (this.readLockerObject)
{
this.ReadFile(e.FullPath);
}
}
}
}
}
private bool ReadFile(string filepath, int count, bool directReading)
{
StreamReader sr = this.OpenStreamReader(file);
if (sr != null)
{
string line;
string[] split;
int signalId;
double value;
while ((line = sr.ReadLine()) != null)
{
// do sth. with line
}
}
}
}
internal class InputFileInfo : IDisposable
{
public string Dir { get; private set; }
public string File { get; private set; }
public FileSystemWatcher Watcher { get; private set; }
public DateTime LastHandledChange { get; set; }
private string fullpath;
public string Fullpath
{
get
{
return this.fullpath;
}
set
{
this.fullpath = BaseHelper.GetFullFilePath(value);
this.Dir = Directory.GetParent(this.fullpath).ToString();
this.File = this.fullpath.Replace(this.Dir + "\\", string.Empty);
this.Watcher = new FileSystemWatcher();
this.Watcher.Path = this.Dir;
this.Watcher.Filter = this.File;
this.Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
this.Watcher.EnableRaisingEvents = true;
}
}
public void Dispose()
{
if (this.Watcher != null)
{
this.Watcher.Dispose();
this.Watcher = null;
}
}
}
公共部分类文件模块
{
私有ConcurrentDictionary inputFileList=新ConcurrentDictionary();
公共文件模块()
{
this.InitializeInputFileWatchers();
}
[权限集(SecurityAction.Demand,Name=“FullTrust”)]
文件监视程序的公共作废启用或SABLERAISINGEVENTS(bool启用)
{
foreach(此.inputFileList中的变量el)
{
el.Value.Watcher.EnableRaisingEvents=启用;
}
}
[权限集(SecurityAction.Demand,Name=“FullTrust”)]
私有void初始化InputFileWatchers()
{
对于(int i=0;i{return info;});
}
}
}
[权限集(SecurityAction.Demand,Name=“FullTrust”)]
私有void OnFileChange(对象源、文件系统目标)
{
输入文件信息;
if(this.inputFileList.TryGetValue(例如FullPath,out info))
{
DateTime lastWriteTime=System.IO.File.GetLastWriteTime(e.FullPath);
if(info.LastHandledChange!=lastWriteTime)
{
TimeSpan=lastWriteTime.Subtract(info.LastHandledChange);
如果(span.Days==0&&span.Hours==0&&span.Minutes==0&&span.Seconds==0&&span.totalMillimes{returninfo;});
锁定(this.readLockerObject)
{
此.ReadFile(e.FullPath);
}
}
}
}
}
私有bool ReadFile(字符串文件路径、整数计数、bool directReading)
{
StreamReader sr=this.OpenStreamReader(文件);
如果(sr!=null)
{
弦线;
字符串[]拆分;
int-signalId;
双重价值;
而((line=sr.ReadLine())!=null)
{
//用线做某事
}
}
}
}
内部类InputFileInfo:IDisposable
{
公共字符串Dir{get;private set;}
公共字符串文件{get;private set;}
公共文件系统监视程序监视程序{get;private set;}
公共日期时间LastHandledChange{get;set;}
私有字符串完整路径;
公共字符串完整路径
{
得到
{
返回这个.fullpath;
}
设置
{
this.fullpath=BaseHelper.GetFullFilePath(值);
this.Dir=Directory.GetParent(this.fullpath.ToString();
this.File=this.fullpath.Replace(this.Dir+“\\”,string.Empty);
this.Watcher=newfilesystemwatcher();
this.Watcher.Path=this.Dir;
this.Watcher.Filter=this.File;
this.Watcher.NotifyFilter=NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
this.Watcher.EnableRaisingEvents=true;
}
}
公共空间处置()
{
如果(this.Watcher!=null)
{
this.Watcher.Dispose();
this.Watcher=null;
}
}
}
行_watcher.EnableRaisingEvents=false(在FileChanged方法末尾)是否正确?我希望它将EnableRaisingEvents设置为true。是的,你是对的。那是个打字错误。我在上面的帖子中也做过同样的编辑。但问题仍然是一样的:(
public partial class FileModule
{
private ConcurrentDictionary<string, InputFileInfo> inputFileList = new ConcurrentDictionary<string, InputFileInfo>();
public FileModule()
{
this.InitializeInputFileWatchers();
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public void EnableOrDisableRaisingEventsForFileWatchers(bool enable)
{
foreach (var el in this.inputFileList)
{
el.Value.Watcher.EnableRaisingEvents = enable;
}
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private void InitializeInputFileWatchers()
{
for (int i = 0; i < this.InputFiles.Count; i++)
{
if (File.Exists(this.InputFiles[i]))
{
InputFileInfo info = new InputFileInfo();
info.Fullpath = ((FileModuleSettings)this.Settings).InputFiles[i];
info.Watcher.Changed += this.OnFileChange;
this.inputFileList.AddOrUpdate(info.Fullpath, info, (e, v) => { return info; });
}
}
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private void OnFileChange(object source, FileSystemEventArgs e)
{
InputFileInfo info;
if (this.inputFileList.TryGetValue(e.FullPath, out info))
{
DateTime lastWriteTime = System.IO.File.GetLastWriteTime(e.FullPath);
if (info.LastHandledChange != lastWriteTime)
{
TimeSpan span = lastWriteTime.Subtract(info.LastHandledChange);
if (span.Days == 0 && span.Hours == 0 && span.Minutes == 0 && span.Seconds == 0 && span.TotalMilliseconds < this.MinimumFileChangePeriod)
{
// Event ignored due to required minimum file change period;
}
else
{
info.LastHandledChange = lastWriteTime;
this.inputFileList.AddOrUpdate(e.FullPath, info, (a, v) => { return info; });
lock (this.readLockerObject)
{
this.ReadFile(e.FullPath);
}
}
}
}
}
private bool ReadFile(string filepath, int count, bool directReading)
{
StreamReader sr = this.OpenStreamReader(file);
if (sr != null)
{
string line;
string[] split;
int signalId;
double value;
while ((line = sr.ReadLine()) != null)
{
// do sth. with line
}
}
}
}
internal class InputFileInfo : IDisposable
{
public string Dir { get; private set; }
public string File { get; private set; }
public FileSystemWatcher Watcher { get; private set; }
public DateTime LastHandledChange { get; set; }
private string fullpath;
public string Fullpath
{
get
{
return this.fullpath;
}
set
{
this.fullpath = BaseHelper.GetFullFilePath(value);
this.Dir = Directory.GetParent(this.fullpath).ToString();
this.File = this.fullpath.Replace(this.Dir + "\\", string.Empty);
this.Watcher = new FileSystemWatcher();
this.Watcher.Path = this.Dir;
this.Watcher.Filter = this.File;
this.Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
this.Watcher.EnableRaisingEvents = true;
}
}
public void Dispose()
{
if (this.Watcher != null)
{
this.Watcher.Dispose();
this.Watcher = null;
}
}
}