FileSystemWatcher not firing events in log file - c#

I am watching for changes in a .log file that is being written by a software of an industrial machine.
The software is continously writing but no changes are detected by FileSystemWatcher.
However, when I open the Windows Explorer and navigate to the watched directory, suddenly FileSystemWatcher detects inmmediatly the last change and fires. (quite strange).
I am configuring the watcher as:
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = "C:\\nextgen\\log";
watcher.NotifyFilter = NotifyFilters.DirectoryName |
NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.FileName |
NotifyFilters.Size |
NotifyFilters.Attributes | NotifyFilters.CreationTime;
// Only watch logfiles.
watcher.Filter = "*.log";
// Add event handlers.
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created+= new FileSystemEventHandler(OnChanged);
// Begin watching.
watcher.EnableRaisingEvents = true;

Related

File Filter for FileSystemWatcher()

I am trying to figure out, how to watch only certain way of files:
e.g.
Folder will populate files with the same name, but different extension (.zip, .another)
The file will have a certain name e.g. ASK_QUESTION_VERSION_XXXXXXX.zip, where the XXXXXX will change.
Since the folder will have different files populated e.g. DIFFERENT_FILE_XXXXXX.zip, with similar naming, I would only want to watch for the first files being placed.
How can I filter this here? Here is a look at the code:
public void watch(List<string> servicesInvolved, int timeout)
{
watcher.Path = sourcePath;
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName
| NotifyFilters.DirectoryName | NotifyFilters.CreationTime;
watcher.Filter = "*.*";
// The below did not work, e.g. compilation errors, could not add two filters.
//watcher.Filter.Add("*.zip");
//watcher.Filters.Add("FileName*");
watcher.Created += (sender, e) => OnChanged(sender, e, servicesInvolved, timeout);
watcher.EnableRaisingEvents = true;
}
This is somehow a simple answer as per #CodeCaster watcher.Filter = MyFolder*Name*.zip;

FileSystemWatcher with the console application

To send bulk email in my web application I am using filewatcher to send the application.
I have planned to write filewatcher with the console application instead of windows service or scheduler.
I have copied the executable file shortcut in the following path.
%appdata%\Microsoft\Windows\Start Menu\Programs
Ref: https://superuser.com/questions/948088/how-to-add-exe-to-start-menu-in-windows-10
After run the executable file the file watcher is not watched always.
After searching some sites, i have found that we need to add the code
new System.Threading.AutoResetEvent(false).WaitOne();
Is this the right method to add in the executable file and to watch the folder?
After run the console application (without above code) is the file won't be watched always?
What will be the right method to use the file watcher?
FileSystemWatcher watcher = new FileSystemWatcher();
string filePath = ConfigurationManager.AppSettings["documentPath"];
watcher.Path = filePath;
watcher.EnableRaisingEvents = true;
watcher.NotifyFilter = NotifyFilters.FileName;
watcher.Filter = "*.*";
watcher.Created += new FileSystemEventHandler(OnChanged);
Since it's a Console Application you need to write a code in the Main method to wait and not to close immediately after running codes.
static void Main()
{
FileSystemWatcher watcher = new FileSystemWatcher();
string filePath = ConfigurationManager.AppSettings["documentPath"];
watcher.Path = filePath;
watcher.EnableRaisingEvents = true;
watcher.NotifyFilter = NotifyFilters.FileName;
watcher.Filter = "*.*";
watcher.Created += new FileSystemEventHandler(OnChanged);
// wait - not to end
new System.Threading.AutoResetEvent(false).WaitOne();
}
Your code only tracks changes in the root folder, if you wanted to watch the subfolders you need to set IncludeSubdirectories=true for your watcher object.
static void Main(string[] args)
{
FileSystemWatcher watcher = new FileSystemWatcher();
string filePath = #"d:\watchDir";
watcher.Path = filePath;
watcher.EnableRaisingEvents = true;
watcher.NotifyFilter = NotifyFilters.FileName;
watcher.Filter = "*.*";
// will track changes in sub-folders as well
watcher.IncludeSubdirectories = true;
watcher.Created += new FileSystemEventHandler(OnChanged);
new System.Threading.AutoResetEvent(false).WaitOne();
}
You must also be aware of buffer overflow. FROM MSDN FileSystemWatcher
The Windows operating system notifies your component of file changes
in a buffer created by the FileSystemWatcher. If there are many
changes in a short time, the buffer can overflow. This causes the
component to losing track of changes in the directory, and it will only
provide the blanket notification. Increasing the size of the buffer with
the InternalBufferSize property is expensive, as it comes from
non-paged memory that cannot be swapped out to disk, so keep the
buffer as small yet large enough to not miss any file change events.
To avoid a buffer overflow, use the NotifyFilter and
IncludeSubdirectories properties so you can filter out unwanted change
notifications.

How to update fileSystemWatch in order to find newly created file in C#?

I have a console app which is checking a logfile for newly updated data, if yes, then copies them in a db.
Currently I'm using FileSystemWatcher to track any changes in the log.
What I would like to do is, to track if a new logfile is created, if yes, then to invoke myMethod() in the new logfile.
Since I'm new in C# I have a question, should a create a second fileSystemWatcher, or there's a way to update the current one in order to include also this case? I already checked stackoverflow and although I found many posts on fileSystemWatcher, I'm not really sure on how to proceed.
Here's my code:
foreach (string path in paths)
{
if (path.Length > 0)
{
logFile.read(path, errorListAndLevel);
FileSystemWatcher logWatcher = new FileSystemWatcher();
logWatcher.Path = Path.GetDirectoryName(path);
logWatcher.Filter = Path.GetFileName(path);
logWatcher.IncludeSubdirectories = false;
logWatcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size;
logWatcher.Changed += new FileSystemEventHandler(delegate (object sender, FileSystemEventArgs e)
{
logFile.myMethod(errorListAndLevel, e.FullPath.ToString());
});
logWatcher.EnableRaisingEvents = true;
}
}
I thought of creating a logWatcher.Created... but it isn't working.
logWatcher.Created += new FileSystemEventHandler(delegate (object sender, FileSystemEventArgs e)
{
logFile.myMethod(errorListAndLevel, e.FullPath.ToString());
});
The problem is the following line
logWatcher.Filter = Path.GetFileName(path);
It filters all files and makes the fileWatcher only whatch that one file. Now this makes the fileWatcher not calling the event Created unless a second a file with the exact same name will be created.
When you comment that line it should work fine.
Additionaly you could do this instead:
logWatcher.Filter = "*.log";
This will filter all files with the ending .log which is what you want from what I can see.

FileSystemWatcher not firing events

For some reason, my FileSystemWatcher is not firing any events whatsoever. I want to know any time a new file is created, deleted or renamed in my directory. _myFolderPath is being set correctly, I have checked.
Here is my current code:
public void Setup() {
var fileSystemWatcher = new FileSystemWatcher(_myFolderPath);
fileSystemWatcher.NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
fileSystemWatcher.Changed += FileSystemWatcherChanged;
fileSystemWatcher.Created += FileSystemWatcherChanged;
fileSystemWatcher.Deleted += FileSystemWatcherChanged;
fileSystemWatcher.Renamed += FileSystemWatcherChanged;
fileSystemWatcher.Filter = "*.*";
fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcherChanged(object sender, FileSystemEventArgs e)
{
MessageBox.Show("Queue changed");
listBoxQueuedForms.Items.Clear();
foreach (var fileInfo in Directory.GetFiles(_myFolderPath, "*.*", SearchOption.TopDirectoryOnly))
{
listBoxQueuedForms.Items.Add(fileInfo));
}
}
You seem to be creating the FileSystemWatcher as a local variable in the setup method. This will of course go out of scope at the end of the method and may well be getting tidied up at that point, thus removing the watches.
Try creating the FSW at a point where it will be persisted (eg a program level variable) and see if that sorts you out.
My problem was that I expected certain actions to cause the FileSystemWatcher Changed event to fire. For example, moving a file (clicking and dragging) from the desktop to the watched location did not raise an event but copying an existing file and pasting a new copy of it (there by creating a new file to the file system and not simply moving an existing one) caused the Changed event to be raised.
My solution was to add every NotifyFilter to my FileSystemWatcher. This way I am notified in all cases where the FileSystemWatcher is able to notify me.
NOTE that it isn't entirely intuitive/obvious as to which filters will notify you for specific cases. For example, I expected that if I included FileName that I would be notified of any changes to an existing file's name...instead Attributes seem to handle that case.
watcher.NotifyFilter = NotifyFilters.Attributes |
NotifyFilters.CreationTime |
NotifyFilters.FileName |
NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.Size |
NotifyFilters.Security;
Use this setter to enable the trigger:
watcher.EnableRaisingEvents = true;
My issue was that I expected it watches subdirectories also but it doesn't do it by default. If you would like to monitor also subdirectories then set IncludeSubdirectories property to true (it's false by default):
fileSystemWatcher.IncludeSubdirectories = true;
We just had a very similar problem, where moving a folder did not trigger the expected events. The solution was to hard copy the entire folder, rather than just moving it.
DirectoryCopy(".", ".\\temp", True)
Private Shared Sub DirectoryCopy( _
ByVal sourceDirName As String, _
ByVal destDirName As String, _
ByVal copySubDirs As Boolean)
' Get the subdirectories for the specified directory.
Dim dir As DirectoryInfo = New DirectoryInfo(sourceDirName)
If Not dir.Exists Then
Throw New DirectoryNotFoundException( _
"Source directory does not exist or could not be found: " _
+ sourceDirName)
End If
Dim dirs As DirectoryInfo() = dir.GetDirectories()
' If the destination directory doesn't exist, create it.
If Not Directory.Exists(destDirName) Then
Directory.CreateDirectory(destDirName)
End If
' Get the files in the directory and copy them to the new location.
Dim files As FileInfo() = dir.GetFiles()
For Each file In files
Dim temppath As String = Path.Combine(destDirName, file.Name)
file.CopyTo(temppath, False)
Next file
' If copying subdirectories, copy them and their contents to new location.
If copySubDirs Then
For Each subdir In dirs
Dim temppath As String = Path.Combine(destDirName, subdir.Name)
DirectoryCopy(subdir.FullName, temppath, true)
Next subdir
End If
End Sub

Deleting the folder being watched by FileSystemWatcher

I'd like to create an application where instead of only watching a root hierarchy folder, ... I watch each folder individually (with watch subfolders turned off)
However, I can't seem to be able to get the delete logic right. I want to be able to delete any folder in the hierarchy, either internally within the application, or externally, say via windows explorer.
When I try either of these, it appears I get locking issues, as the delete commands fail to execute.
If I disable the watching, then everything seems to work. So I'm assuming the problem is trying to delete a folder that is being watched.
Is there anyway of getting around this? I'd ideally like the fileSystemWatcher to automatically stop watching when the folder its watching has been deleted.
public MainWindow()
{
InitializeComponent();
fsw1 = new FileSystemWatcher()
{
Path = "Folder",
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.FileName | NotifyFilters.DirectoryName,
IncludeSubdirectories = false,
Filter = "",
EnableRaisingEvents = true
};
fsw1.Deleted += new FileSystemEventHandler(OnFileSystemItemDeleted);
fsw2 = new FileSystemWatcher()
{
Path = "Folder/Folder",
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.FileName | NotifyFilters.DirectoryName,
IncludeSubdirectories = false,
Filter = "",
EnableRaisingEvents = true
};
fsw2.Deleted += new FileSystemEventHandler(OnFileSystemItemDeleted);
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
//fsw1.EnableRaisingEvents = false;
//fsw2.EnableRaisingEvents = false;
System.IO.Directory.Delete("Folder", true);
}
void OnFileSystemItemDeleted(object sender, FileSystemEventArgs e)
{
}
FileSystemWatcher fsw1, fsw2;
Currently, you are using fsw1 and fsw2 in order to watch data of any type that might get deleted at any point of time.
Although, i do not see the point of creating a FSW for each folder, here is an answer that might help:
In order to watch for the folders themselves, you need to create a FSW for each folder you would like to observe.
You can then setup the NotifyFilter of the FSW to DirectoryName as follows: folderSystemWatcher.NotifyFilter = NotifyFilter.DirectoryName
see an example of this here.
So one of the FSWs tell you that a folder is deleted, you can then stop, dispose or do whatever to the FSW that is watching that deleted folder.
I did not try that out, but this is how i would have done it, i guess...

Categories