I am creating an application that will watch for file changes in a directory although while files with an extension are detected, folders are not.
using System;
using System.IO;
using System.Diagnostics;
namespace fileSystemWatcherTest
{
class myClass
{
static void Main()
{
using var watcher = new FileSystemWatcher(#"C:\Users\Username\Desktop\Watching folder");
watcher.NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.FileName
| NotifyFilters.LastWrite;
watcher.Changed += onChanged;
watcher.Created += onCreated;
watcher.Error += onError;
watcher.Filter = "";
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
private static void onChanged(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
Console.WriteLine($"Changed: {e.FullPath}");
string fileExtension = Path.GetExtension(e.FullPath);
if (fileExtension != string.Empty)
{
Console.WriteLine(fileExtension);
}
}
private static void onCreated(object sender, FileSystemEventArgs e)
{
Console.WriteLine($"Created: {e.FullPath}");
}
private static void onError(object sender, ErrorEventArgs e)
{
printException(e.GetException());
}
private static void printException(Exception ex)
{
if (ex != null)
{
Console.WriteLine("ERROR");
Console.WriteLine($"Message: {ex.Message}");
Console.WriteLine($"StackTrace:");
Console.WriteLine(ex.StackTrace);
Console.WriteLine("");
printException(ex.InnerException);
}
}
}
}
According to the documentation and the intellisense directories should be detected.
I believe that the problem is with the Filter property but i can't get it to work so i would appreciate some help.
To detect directories as well, you need to add NotifyFilters.DirectoryName to watcher.NotifyFilter:
watcher.NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.DirectoryName
| NotifyFilters.FileName
| NotifyFilters.LastWrite;
Checkout the documentation of NotifyFilters.
Related
I am working on a .NET WPF project using Visual Studio 2022 and I added tray icon functionality to my app. I am managing tray icon part in mainwindow.xaml.cs but i need to track file changes in my mainviewmodel class as well. How can i pass this event to mvvm or maybe pass data to mainviewmodel ? Any help would be appreciated.
public void CreateFileWatcher(string path)
{
watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = nameof(AppStateModel);
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
Thread.Sleep(1000);
var appState = CheckAppState();
AppState = appState;
string workingDirectory = Environment.CurrentDirectory;
string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;
var path = Path.Combine(projectDirectory, "Assets");
switch (appState)
{
case 1:
m_notifyIcon.Icon = new System.Drawing.Icon(Path.Combine(path, "48x48_active.ico"));
break;
case 2:
m_notifyIcon.Icon = new System.Drawing.Icon(Path.Combine(path, "48x48_inactive.ico"));
break;
case 4:
m_notifyIcon.Icon = new System.Drawing.Icon(Path.Combine(path, "48x48_running.ico"));
break;
default:
break;
}
}
private int CheckAppState()
{
try
{
var tempFile = Path.Combine(AppWizard.Default.FolderPath, nameof(AppStateModel));
if (!File.Exists(tempFile))
return -1;
var _path = tempFile;
using (var stream = new FileStream
(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var appStateModel = JsonConvert.DeserializeObject<AppStateModel>(File.ReadAllText(tempFile));
if (appStateModel != null)
{
if (appStateModel.CurrentState == AppStates.Ready)
return 1;
else if (appStateModel.CurrentState == AppStates.Dead || appStateModel.CurrentState == AppStates.Expired)
return 2;
else if (appStateModel.CurrentState == AppStates.Busy)
return 4;
}
}
}
catch (Exception ex)
{
FileLogger.Default.WriteExceptionLog(ex);
}
return -1;
}
A watcher service may look as following:
public class FileWatcherService
{
FileSystemWatcher watcher;
public FileWatcherService()
{
CreateFileWatcher();
}
public event EventHandler<FileSystemEventArgs> FileChanged;
public void CreateFileWatcher()
{
watcher = new FileSystemWatcher(#"C:\Temp");
watcher.NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.DirectoryName
| NotifyFilters.FileName
| NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.Security
| NotifyFilters.Size;
watcher.Changed += MakeANote;
watcher.Created += MakeANote;
watcher.Deleted += MakeANote;
watcher.Renamed += MakeANote;
watcher.Filter = "*.*";
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
}
private void MakeANote(object sender, FileSystemEventArgs e)
{
FileChanged?.Invoke(this, e);
}
}
A simple way is to put the "watcher" in the View Model :
public class MainViewModel :Binding
{
FileWatcherService _fileWatcherService = new FileWatcherService();
public MainViewModel()
{
_fileWatcherService.FileChanged += OnFileChanged;
}
private void OnFileChanged(object sender, FileSystemEventArgs e)
{
LastAction = e.ChangeType.ToString();
File = e.Name;
}
string _lastAction;
public string LastAction
{
get { return _lastAction; }
set { _lastAction = value;NotifyPropertyChanged(nameof(LastAction)); }
}
string _file;
public string File
{
get { return _file; }
set { _file = value; NotifyPropertyChanged(nameof(File)); }
}
}
And the sample XAML code will be as following:
<Grid>
<Grid.DataContext>
<local:MainViewModel/>
</Grid.DataContext>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding File}"/>
<TextBlock Text=" has "/>
<TextBlock Text="{Binding LastAction}"/>
</StackPanel>
</Grid>
I am trying to monitor all files created/deleted/renamed in a folder using FileSystemWatcher in a docker volume. It is picking up events on the root dir (most of the time) that is being watched but nothing in subdir triggers an event even though IncludeSubdirectories = true. The watcher is saved as a prop. How can I get it to watch the subdir and trigger on all events not just most?
public void StartMonitorService()
{
Watcher = new FileSystemWatcher(#"/var/lib/docker/volumes/monitor");
Watcher.NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.DirectoryName
| NotifyFilters.FileName
| NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.Security
| NotifyFilters.Size;
Watcher.Created += OnCreated;
Watcher.Deleted += OnDeleted;
Watcher.Renamed += OnRenamed;
Watcher.Filter = "";
Watcher.IncludeSubdirectories = true;
Watcher.EnableRaisingEvents = true;
}
I didn't quite solve my question, but I have a work around for anyone who might have had the same issue I did.
private void OnCreated(object sender, FileSystemEventArgs e)
{
if (Directory.Exists(e.FullPath))
{
string dirRoot = e.FullPath;
DateTime lastTimeWriten = Directory.GetLastWriteTime(dirRoot);
while (true)
{
Thread.Sleep(30000);
if (lastTimeWriten == Directory.GetLastWriteTime(dirRoot))
break;
lastTimeWriten = Directory.GetLastWriteTime(dirRoot);
}
HashSet<string> fileSet = new HashSet<string>(Directory.GetFileSystemEntries(dirRoot, "*", SearchOption.AllDirectories));
...
_messageService.SendNewSurveyMessage(newSurveyFileSet);
}
}
I have this code to detect deleteing files.
m_Watcher = new System.IO.FileSystemWatcher();
m_Watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
m_Watcher.Changed += new FileSystemEventHandler(OnCreated);
m_Watcher.Created += new FileSystemEventHandler(OnChanged);
m_Watcher.Deleted += new FileSystemEventHandler(OnDeleted);
m_Watcher.Renamed += new RenamedEventHandler(OnRenamed);
m_Watcher.EnableRaisingEvents = true;
private void OnDeleted(object sender, FileSystemEventArgs e)
{
Debug.WriteLine(e.FullPath);
}
private void OnChanged(object sender, FileSystemEventArgs e)
{
Debug.WriteLine(e.FullPath);
}
But when I delete multiple files using Shift it detects 1 file only.
I know that it should be corrected via WaitForChanged method but I have no clue how to implement it.
The classic code does not help https://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.deleted(v=vs.110).aspx
Thanks for help!
I found working solution here
FileSystemWatcher - Pure Chaos (Part 1 of 2)
http://www.codeproject.com/Articles/58740/FileSystemWatcher-Pure-Chaos-Part-of
I have written this code for watching files in my system, but its not alerting any modificationms in the folder or file. How can I achieve this? I am not understanding as it does not show any exceptions or errors.
static void Main(string[] args)
{
FileSystemWatcher();
}
public static void FileSystemWatcher()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"D:\watcher";
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.*";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
Console.Read();
}
private static void OnChanged(object sender, FileSystemEventArgs e)
{
Console.WriteLine(e.Name + " has changed");
}
I updated the code. The NotifyFilter needs to be expanded if you want to see new files added
static void Main(string[] args)
{
FileSystemWatcher();
}
public static void FileSystemWatcher()
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"D:\temp";
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.*";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += Watcher_Created;
watcher.Renamed += Watcher_Renamed;
watcher.EnableRaisingEvents = true;
Console.Read();
}
private static void Watcher_Renamed(object sender, RenamedEventArgs e)
{
Console.WriteLine(e.Name + " has been renamed");
}
private static void Watcher_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine(e.Name + " has been added");
}
private static void OnChanged(object sender, FileSystemEventArgs e)
{
Console.WriteLine(e.Name + " has changed");
}
FileSystemWatcher.NotifyFilter Property
watcher.NotifyFilter <- is flag enum!
You need to write:
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
...
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
I want to send a file which has been found when the System Watcher has discoverd a created file ending with ".txt", ".doc" or ".docx". My Problem is that the System Watcher discover just files ending with ".txt".
Here is my Code:
private String Attachmenttosend
{
get { return attachmentfile; }
set { attachmentfile = value; }
}
private void NewFileSystemWatcher()
{
String filter = "*.txt,*.doc,*.docx";
string[] FileExtension = filter.Split(',');
for (int i = 0; i < FileExtension.GetLength(0); i++)
{
watcher = new FileSystemWatcher(folder); // on its own Thread
watcher.Created += new FileSystemEventHandler(NewEMail);
attachmenttosend.Add(Attachmenttosend);
watcher.Filter = FileExtension[i];
watcher.EnableRaisingEvents = true;
watchlist.Add(watcher);
}
Send(Attachmenttosend);
}
private void NewEMail(Object source, FileSystemEventArgs e)
{
while (Locked(e.FullPath)) // check if the file is used
{
Thread.Sleep(10);
}
Attachmenttosend = e.FullPath; // store the filename
}
I think this will help you,just create a console app on the fly and paste this in and try it out:
private static string[] filters = new string[] { ".txt", ".doc", ".docx" };
static void Main(string[] args)
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"C:\...\...\...";//your directory here
/* Watch for changes in LastAccess and LastWrite times, and
the renaming of files or directories. */
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
//dont set this
//watcher.Filter = "*.txt";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.Deleted += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
watcher.EnableRaisingEvents = true;
Console.ReadKey();
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
if(filters.Contains(Path.GetExtension(e.FullPath)))
{
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
//Attachmenttosend = e.FullPath;
}
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
if (filters.Contains(Path.GetExtension(e.FullPath)))
Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
}
Also as Kunal pointed out
attachmenttosend.Add(Attachmenttosend);
I guess from the uppercase and lower case that you are trying to add to the backing field of the property its own property,dont,also...you dont add to a string only += (concat).
Unless attachmenttosend is a for example a list of strings.