FileSystemWatcher IncludeSubdirectories not working on network share - c#

I'm attempting to watch a network share for folders where a file is added to the share to indicate the upload is complete. I wanted to use a FileSystemWatcher to monitor that share and its subdirectories for that trigger file, as shown below.
FileSystemWatcher fsw = new FileSystemWatcher(share, triggerFilePattern);
fsw.IncludeSubdirectories = true;
fsw.Created += new FileSystemEventHandler(OnCreated);
fsw.Renamed += new RenamedEventHandler(OnRenamed);
fsw.Error += new ErrorEventHandler(OnError);
If a file is created at the root of the share, the event triggers. If a file is created within a subdirectory of the share, the event does not trigger, and I don't get an error either.
If I create a new FileSystemWatcher for that subdirectory, then I do receive an event when a file is created there. But, similar to the top level FileSystemWatcher, I won't get events for files created in any further subdirectories.
If I change the network share to a local directory for testing, it does work as expected.
Any ideas? Could I have set up some wonky network share setting that blocks recursive FileSystemWatcher checks? I can work around this, but it would be nice to not have to complicate the code.
Edit: I saw that I didn't have Full Control under Properties->Security tab, so I thought that could be it. But I was able to get normal desired behavior on a different share with the same visible permissions, so I'm back to not knowing why this specific share isn't working.
Edit2: At a coworker's suggestion, I added a Changed handler too. Doesn't make sense to me how a file can be changed without getting Created first, but... I'm getting Changed events on the share in question when creating files in a subdirectory. (And I'm still getting nothing when renaming them.) This solves my immediate problem, but I'm going to leave the question open in case someone's able to answer why that's happening.

Try this
private static FileSystemWatcher fw;
static void Main(string[] args)
{
fw = new FileSystemWatcher(#"D:\Folder_Watch");
fw.IncludeSubdirectories = true;
fw.NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
fw.Created += fw_Created;
fw.Changed += fw_Created;
fw.Renamed += fw_Created;
fw.Filter = "*.*";
fw.EnableRaisingEvents = true;
new System.Threading.AutoResetEvent(false).WaitOne();
}
static void fw_Created(object sender, FileSystemEventArgs e)
{
try
{
fw.EnableRaisingEvents = false;
//Your Code
}
finally
{
fw.EnableRaisingEvents = true;
}
}

I had same problem and I solved it by giving write permission to the shared network folder (it had only read permission so far). Shared folder is originally on Linux but I have it mounted on Windows Server 2008 R2 where I'm running program with FileSystemWatcher.

Related

Is it possible to watch a file, to see when it is being read?

I have a file, it is large, reading it takes a long time and I'd like to have some monitoring to see when it's being written to.
I can solve this quite easily by chucking some logging into the application that it reading it, however I'd like something more agnostic. There are quite a few application that have a similar use case. Monitoring writes should be easy enough as I can watch the last modified date, but reading isn't so easy.
If there any way to passively monitor read and writes to a file?
To clarify: If it can do done in 100% C#, then great, if not then shelling out to some other 'thing', or even resorting to some other language is fine. I don't really mind what the watching bit is written in.
Trying Rahul's Solution
I have set up ithe following test code. It dumps events to the console:
public static void Main()
{
var taskFactory = new TaskFactory();
var setup = new Action(() =>
{
var setupWatcher =
new Action<NotifyFilters, string, FileSystemWatcher>((filters, s, watcher) =>
{
watcher.EnableRaisingEvents = true;
watcher.NotifyFilter = filters;
watcher.Changed += (sender, args) => System.Console.WriteLine(s, args.FullPath, args.ChangeType);
});
var lastAccessWatcher = new FileSystemWatcher(BASE_PATH);
setupWatcher(NotifyFilters.LastAccess,
"File: {0}\tFilter: LastAccess\tType: {1}", lastAccessWatcher);
var lastWriteWatcher = new FileSystemWatcher(BASE_PATH);
setupWatcher(NotifyFilters.LastWrite, "File: {0}\tFilter: LastWrite\tType: {1}",
lastWriteWatcher);
var fileNameWatcher = new FileSystemWatcher(BASE_PATH);
setupWatcher(NotifyFilters.FileName,
"File: {0}\tFilter: FileName\tType: {1}", fileNameWatcher);
var directoryNameWatcher = new FileSystemWatcher(BASE_PATH);
setupWatcher(NotifyFilters.LastWrite, "File: {0}\tFilter: DirectoryName\tType: {1}",
directoryNameWatcher);
});
taskFactory.StartNew(setup);
while (true)
{
Thread.Sleep(10);
}
}
However, when I open a text file in notepad, no event is thrown by the lastAccessWatcher, whereas, when I save, two events are thrown by the lastWriteWatcher and the directoryNameWatcher, as per below.
File: F:\FileMonitor\New Text Document.txt Filter: LastWrite Type: Changed
File: F:\FileMonitor\New Text Document.txt Filter: LastWrite Type: Changed
File: F:\FileMonitor\New Text Document.txt Filter: DirectoryName Type: Changed
File: F:\FileMonitor\New Text Document.txt Filter: DirectoryName Type: Changed
So...
What does trigger 'last access'
Can I actually have any trigger fired when a file is read?
For watching writes to the file, the FileSystemWatcher class is the right way to go. However if you want to know if a file is being written, what I would do is get a list of all the open files by process, and monitor when the file is opened and then closed.
There is a CodeProject article that shows how to get the open files by process here.
One solution would be to use a Microsoft tool called Process Monitor. It's able to list all CreateFile/ReadFile/WriteFile calls any process does. There are several command line options available:
You can use the FileSystemWatcher class
Listens to the file system change notifications and raises events when
a directory, or file in a directory, changes.
You can use the different events
Changed
Created
Deleted
Renamed
and also read this FileSystemWatcher Tips
An example:
public void MyFileWatcher(string path)
{
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "myFile.txt";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
Console.WriteLine(e.FullPath + " " + e.ChangeType);
}
Similarly you can add other event handlers definition.
Also if you want to check the read then you can use the FileInfo.LastAccessTime and FileInfo.Refresh() in a polling loop to get the information of when your file is being read.
In code your task is handled with a filesystem filter driver. Process Monitor application (already mentioned in another answer) includes such driver in pre-built form.
You can write a kernel-mode driver yourself, yet this would probably be an overkill. Then there exists our CallbackFilter - a class library with a pre-created kernel-mode driver included. You write code in C# and catch all filesystem operations before or after they are performed. If your need is short-term, then the evaluation license will work.

FileSystemWatcher gets subdirectory events even though IncludeSubdirectories is set to false

I have the following FileSystemWatcher setup in my windows service.
FileSystemWatcher Watcher = new FileSystemWatcher();
Watcher.Path = watcherDir;
Watcher.NotifyFilter = NotifyFilters.LastWrite;
Watcher.Renamed += Watcher_Renamed;
Watcher.Changed += Watcher_Changed;
Watcher.Error += Watcher_Error;
Watcher.Filter = "*.*";
Watcher.IncludeSubdirectories = false;
Watcher.EnableRaisingEvents = true;
I see some inconsistent behavior - it listens to changes in subdirectories too. I have logged to see what it finds it is bit odd.
I am watching C:\Temp\Folder1, and some other process creates a log file in C:\Temp\Folder1\Folder2. This FileSystemWatcher object is picking this info up -
1. e.FullPath gives the name of the subdirectory, in this case C:\Temp\Folder1\Folder2
2. Path.GetDirectoryName(e.FullPath) gives me the directory that I am actually watching for i.e. C:\Temp\Folder1.
3. The extension is empty and that is how I ignore this and this is how I ignore this case.
Any suggestions for how else I can figure out what is going on here?
The creation or deletion of a file within a directory is also counted as a change to that directory itself. That's the event that's being reported to you. Folder2, itself, is within the directory that you're monitoring.
The reported path is the path of the directory, not the file within it, and you'll notice that its your Changed handler being invoked, despite the fact that the file system operations are actually creation or deletion.
In your event handler, you could just check whether the reported path is a directory, and just return and perform no further processing in the event handler, if that's the case.

FIleSystemWatcher last access (read) for media files is not working

I am delivering media contents to a client system (download from internet) and want to acknowledge if the media file was opened (and viewed) by the operator.
I am using a file system watcher (C# 3.5) to check for the last access time of file (so whenever the media file is played I should get the event) and I send an acknowledgement.
I have enabled the last access time in registry of my Windows 7 machine here and rebooted my system. File system watcher fires events on directory opened but not on media play.
Here is my code :
private FileSystemWatcher fsWatcher = null;
private static Object objLock = new Object();
private void StartAccessWatcher(string _folderPath)
{
fsWatcher = new FileSystemWatcher(_folderPath, "*.*");
fsWatcher.Changed += new FileSystemEventHandler(fsWatcher_Changed);
fsWatcher.IncludeSubdirectories = true;
fsWatcher.NotifyFilter = NotifyFilters.LastAccess;
fsWatcher.EnableRaisingEvents = true;
}
private void fsWatcher_Changed(object sender, FileSystemEventArgs e)
{
lock (objLock)
{
fsWatcher.EnableRaisingEvents = false;
DisplayMessage(string.Concat(e.ChangeType, " ", e.FullPath));
fsWatcher.EnableRaisingEvents = true;
}
}
private void btn_StartWatcher_Click(object sender, EventArgs e)
{
StartAccessWatcher(#"E:\Surewaves\Media-Store\MP1 Videos");
}
You may also download my code sample from here.
Please tell me how best can I achieve it ? I need to get the the last access time (when ever the video or audio or image or .swf file was played by any player) ?
As an update to this three year old question, the code given works correctly now* with videos played on the local machine.
The machine must have lastAccess successfully enabled with the following command
fsutil behavior set DisableLastAccess 0
as noted in the question.
*- at the time of this post, using Windows Server 2012 R2
The FileSystemWatcher is used to watch for changes in a specified directory. You can watch for changes in files and subdirectories of the specified directory. In your case there is no change being made on media files. I would suggest try extending FileSystemWatcher class and create new events for media file reading and then fire those events.

FileSystemWatcher event on adding a folder with subdirectories

I'm using a FileSystemWatcher to monitor a directory for new folders created. This would work just fine, except that each of these folders can have one or more subdirectories inside of them.
The problem is that when I copy the top level folder (with one or more subdirectories in it) the FileSystemWatcher only catches the addition of the top level folder and not the subdirectories.
Ex: Drag folder 'foo' with subdirectory 'bar' into directory being watched
FileSystemWatcher notifies that new directory 'foo' was created, but says nothing about 'bar'
Am I missing something with the functionality of FileSystemWatcher or is there some other way around this?
You also need to handle OnRenamed, as well as IncludeSubdirectories.
From MSDN:
Copying and moving folders
The operating system and FileSystemWatcher object interpret a
cut-and-paste action or a move action as a rename action for a folder
and its contents. If you cut and paste a folder with files into a
folder being watched, the FileSystemWatcher object reports only the
folder as new, but not its contents because they are essentially only
renamed.
To be notified that the contents of folders have been moved or copied
into a watched folder, provide OnChanged and OnRenamed event handler
methods...
Setting IncludeSubdirectories does not work in this specific case.
Here's a sample i set up:
static void Main(string[] args)
{
FileSystemWatcher fsw = new FileSystemWatcher(#"C:\Temp", "*.*");
fsw.EnableRaisingEvents = true;
fsw.Created += new FileSystemEventHandler(fsw_Created);
fsw.Renamed += new RenamedEventHandler(fsw_Renamed);
fsw.Changed += new FileSystemEventHandler(fsw_Changed);
fsw.IncludeSubdirectories = true;
Console.ReadLine();
}
static void fsw_Changed(object sender, FileSystemEventArgs e)
{
Console.WriteLine("{0} was changed.", e.FullPath);
}
static void fsw_Renamed(object sender, RenamedEventArgs e)
{
Console.WriteLine("{0} was renamed.", e.FullPath);
}
static void fsw_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine("{0} was created", e.FullPath);
}
In this case, if i move foo that contains bar folder in it into C:\Temp, i will only be notified of C:\Temp\Foo created.
FileSystemWatcher is not sealed, if this functionality is vital, i would subclass it and extend it to check under created folders, and raise events for them as well (or something similar to this implementation).
You need to set IncludeSudirectories which will get or set a value whether the subdirectories will be monitored.
You need to set the IncludeSubdirectories property.
Take a look at this link
"Set IncludeSubdirectories to true when you want to watch for change notifications for files and directories contained within the directory specified"
watcher.IncludeSubdirectories = true;
As far as I know you there is no way to tell the FileSystemWatcher to notify you for every element in a directory that has been changed.
If the element modified is a directory, you have to do the browsing on your own (which is not terribly hard).
IncludeSubdirectories only tells you about modifications of files and folders within the element watched - but alas not if it has been copied in in one move. In your example, when you watch foo and somebody adds a file to bar (later on) and you have set IncludeSubdirectories you will be notified of that change.
hth
Mario

FileNotFoundException in FileSystemWatcher

I am using a FileSystemWatcher on a directory and added its event handlers, set its EnableRaisingEvents=true; and IncludeSubdirectories=false; and added NotifyFilters.
While running the application if I create new folders in the specified directory sometime I get
FileNotFoundException : "An error occurred while reading a directory".
System.IO.FileSystemWatcher.StartRaisingEvents()
System.IO.FileSystemWatcher.set_EnableRaisingEvents(Boolean value)
What can be root cause of the problem?
What is StartRaisingEvents()?
Just out of stupidity, I googled it before thinking.
In my case, Path was being defined after EnableRaisingEvents.
e.g. won't throw an exception:
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"C:\";
//...
watcher.EnableRaisingEvents = true;
This will:
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.EnableRaisingEvents = true;
//...
watcher.Path = #"C:\";
So. since I like to fail-fast instead of letting the next one figure out what the hell is happening, I modified that after path declaration:
var watcher = new FileSystemWatcher();
watcher.Path = #"C:\Users\me";
if (string.IsNullOrWhiteSpace(watcher.Path))
throw new InvalidOperationException($"You must define a path.");
if (!Directory.Exists(watcher.Path))
throw new InvalidOperationException($"Directory {watcher.Path} does not exist.");
watcher.EnableRaisingEvents = true;
Stupid issue, but at least I gave some quirky fail-fast solution.
This is typically because the FileSystemWatcher can be unreliable. The folder may not "fully" exist when you get the events. You may need to retry with sufficient pauses and do various Directory.Exists() checks before actually performing IO operations.
I've got quite the same problem and finally I found out that the problem was with the path.
The Directory.Exist() give answer that the directory exist... even if the path got a empty char in the end of the string but the FileSystemWatcher couldn't manage it.
So obviously the Directory.Exist() trim the path but the Watcher don't. In my case removing of the empty chars solve the problem.
Hopefully it could help somebody.
For me it was some mystery where, I guess a directory was named with some invalid character(s). Directory.Exists(watchDirectory) would return true, but the FileWatcher would blow up with the error above.
The "fix" was to delete the directory and recreate it with the same name :)

Categories