I am using FileSystemWatcher
.
All is working fine. When I save my file, the Changed event is raised properly. But if I save file a second time, the Changed event isn't raised anymore.
Do I need to put additional code, so it would raise everytime I save a file?
Here is a part of my code, if this would be of any help :
I made a class MachineWatcher
, because in my project, I need to create a list of different watcher types (but I don't think it changes anything to the question) :
public class MachineWatcher
{
private Machine machine { get; set; }
public Machine Machine { get { return this.machine; } set { this.machine = value; } }
private string typeWatcher { get; set; } = "";
public string TypeWatcher { get { return this.typeWatcher; } set { this.typeWatcher = value; } }
FileSystemWatcher watcher { get; set; }
public FileSystemWatcher Watcher { get { return this.watcher; } set { this.watcher = value; } }
public MachineWatcher()
{
}
public MachineWatcher(string type,string directoryStock,string fileFilter)
{
this.typeWatcher = type;
this.watcher = new FileSystemWatcher();
this.watcher.Path = Path.GetDirectoryName(directoryStock);
this.watcher.Filter = fileFilter;
this.watcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime;
this.watcher.Changed += new FileSystemEventHandler(OnFeedBackNesterCreated);
this.watcher.Created += new FileSystemEventHandler(OnFeedBackNesterCreated);
this.watcher.EnableRaisingEvents = true;
}
private void OnFeedBackNesterCreated(object source, FileSystemEventArgs e)
{
string filePath = e.FullPath;
LaunchingOrder newLo = this.readXmlFile(filePath);
if(newLo!=null)
{
newLo.Fichier = filePath;
newLo.AddOrUpdate();
}
}
}
My suggestion is to try adding this.watcher.Renamed
to the events that are handled, and then take care not to filter out the Renamed
event when you apply the this.watcher.NotifyFilter
expression. This will at least compensate for the way Excel performs a Save
operation called from its menu. Based on the test methodology shown below, the Changed
event will never be fired. When I made a mock MachineWatcher
and hooked up all the events including Renamed
, the first events occur when a temporary file named ~$ExcelTestFile.xlsx is created when opening the file. Then, every time a Save
operation happens, the following sequence takes place:
Created
event for temporary file (for example, on this pass it's arbitrarily named ECA83C30).Changed
events (presumably as the modified version of the main file is copied to it).Renamed
event for D03DF176.tmp (presumably from ECA83C30)Renamed
event for the real target, a file named ExcelTestFile.xlxs (presumably a copy operation from D03DF176.tmp)Delete
event for D03DF176.tmpBut no Change
events for the target Excel file even though it ends up with a new LastWriteTime
. This was a shocker to me, but see if you can repro!
Mock a minimal MachineWatcher
public class MachineWatcher
{
public MachineWatcher(string type, string directoryStock, string fileFilter)
{
watcher = new FileSystemWatcher(directoryStock, fileFilter);
watcher.Created += onModified;
watcher.Changed += onModified;
watcher.Renamed += onModified;
watcher.Deleted += onModified;
// watcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime;
watcher.EnableRaisingEvents = true;
}
FileSystemWatcher watcher { get; }
private void onModified(object sender, FileSystemEventArgs e)
{
switch (e.ChangeType)
{
case WatcherChangeTypes.Created:
OnFeedBackNesterCreated(sender, e);
Console.WriteLine($" LastWriteTime: {new FileInfo(e.FullPath).LastWriteTime}");
break;
case WatcherChangeTypes.Deleted:
Console.WriteLine($"Deleted: {e.Name}");
break;
case WatcherChangeTypes.Changed:
var ext = Path.GetExtension(e.FullPath);
switch (ext)
{
case ".xlsx":
Console.Write($"Changed: {e.Name}");
break;
case ".txt":
try
{
Console.Write($"Changed: {e.Name} {File.ReadAllLines(e.FullPath).Last()}");
}
catch
{
Console.Write($"Changed: {e.Name} (in transition)");
}
break;
case "":
Console.Write($"Changed: {e.Name} (no extension)");
break;
default:
Console.Write($"The '{ext}' extension is not supported");
break;
}
Console.WriteLine($" LastWriteTime: {new FileInfo(e.FullPath).LastWriteTime}");
break;
case WatcherChangeTypes.Renamed:
Console.Write($"Renamed: {e.Name}");
Console.WriteLine($" LastWriteTime: {new FileInfo(e.FullPath).LastWriteTime}");
break;
default:
break;
}
}
private void OnFeedBackNesterCreated(object source, FileSystemEventArgs e)
{
Console.Write($"Created: {e.Name}");
}
}
Exercise the MachineWatcher
using Console
static void Main(string[] args)
{
const int SPACING = 500;
string appData = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"custom_file_system_watcher");
// Ensure that the root directory exists
Directory.CreateDirectory(appData);
// Make an instance of MachineWatcher
var mw = new MachineWatcher(
null, // In minimal reproducible sample this is unused
appData,
"*.*");
// Force Delete (if exists)
var testFile = Path.Combine(appData, "testFile.txt");
File.Delete(testFile);
Thread.Sleep(SPACING);
// Force Create + Change
File.WriteAllText(
testFile,
$"{DateTime.Now}{Environment.NewLine}");
Thread.Sleep(SPACING);
// Force N Changes
var N = 5;
for (int i = 1; i <= N; i++)
{
// Using Append because File.WriteAllText is two events not one.
File.AppendAllText(testFile, $"Change #{i}{Environment.NewLine}");
Thread.Sleep(SPACING);
}
// Force Rename
var testFileRenamed = Path.Combine(appData, "testFile.Renamed.txt");
File.Copy(testFile, testFileRenamed, overwrite: true);
Thread.Sleep(SPACING);
// Prove that if the Excel file LastWriteTime changes, we'll see it
var excelFile = Path.Combine(appData, "ExcelTestFile.xlsx");
var fileInfo = new FileInfo(excelFile);
if(fileInfo.Exists)
{
Console.WriteLine();
Console.WriteLine("Proves that if the Excel file LastWriteTime changes, we'll see it:");
try
{
fileInfo.LastWriteTime = DateTime.Now;
}
catch
{
Console.WriteLine("CANNOT CHANGE TIMESTAMP: EXCEL FILE IS ALREADY OPEN");
}
}
Thread.Sleep(SPACING);
Console.WriteLine();
Console.WriteLine("Waiting for Excel file changes...");
Console.ReadKey();
}