Xamarin Forms FileSystemWatcher - c#

i need to watch a folder that are inside my ios/android application.
I would like to use FileSystemWatcher.
This is my code:
var DocFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var InboxFolder = DocFolder + "/Inbox";
FileSystemWatcher watcher = new FileSystemWatcher() {
Path = InboxFolder,
NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,
Filter = "*.*",
EnableRaisingEvents = true
};
watcher.Created += (object sender, FileSystemEventArgs e) => {
// do stuff
};
When the FileSystemWatcher is initializated this error is triggered:
System.NotImplementedException: The method or operation is not implemented.
How can I make this works?
There is another way to watch a folder?
Thank you!

FileSystemWatcher is a .NET Framework-based class which is currently not implemented in Xamarin, although the API is available in .NET Standard 2.0.
In UWP you can create a StorageFolderQuery with ContentChanged event handler to observe changes in a given folder. See documentation here.
Android has it's own alternative implementation in the form of Android.OS.FileObserver.
iOS does not seem to have anything out of the box, so this will probably either require you to find a library that does this job for you or to implement such functionality yourself, albeit in a less efficient manner than if it were built-in to the SDK.

Related

FileSystemWatcher not working even once except for root folder having 320K subdirectories

I am using below code to monitor changes happening in a directory including subdirectories. Currently, I am running three different copies of this application and two of them are working fine. Application for which it is not working contains more than 320K subdirectories in it.
I tried to increase InternalBufferSize but nothing happens.
It is working at the root folder and not working for any of the subdirectories.
Also, 2 other copies of the same application monitoring different network paths on different geographical locations are working fine including subdirectories as well.
FileSystemWatcher watcher = new FileSystemWatcher
{
Path = path,
IncludeSubdirectories = true,
Filter = "*.txt",
NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite |
NotifyFilters.FileName | NotifyFilters.DirectoryName
};
watcher.Created += Watcher_Created;
watcher.Changed += Watcher_Changed;
watcher.Deleted += Watcher_Deleted;
watcher.Renamed += Watcher_Renamed;
watcher.Error += Watcher_Error;
watcher.EnableRaisingEvents = true;
PS: Polling is not an option. It takes 3 days to scan entirely 320K directories.
The root-level folder has 2000 plus subdirectories and each subdirectory has up-to 8 levels of subfolders in it
Edit-1:I have checked with the INFRA team and got to know that shared folders are on EMC Isilon NAS storage.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/38adb37d-bbfc-40d6-8b32-a5c1c7d8d4a3/are-there-any-limitations-of-filesystemwatcher-monitoring-a-unc-path-on-nas-server?forum=netfxbcl
Instead of executing the event handlers synchronously, it may help to offload them to the ThreadPool. This will minimize the risk of overflowing the internal buffer of the FileSystemWatcher. The Offload method below could be used for this purpose:
public static FileSystemEventHandler Offload(FileSystemEventHandler handler)
{
return (s, e) => ThreadPool.QueueUserWorkItem(_ => handler(s, e));
}
Usage example:
var fsw = new FileSystemWatcher(path);
fsw.Created += Offload((s, e) =>
{
Console.WriteLine($"Created: {e.Name}");
});
This is not intended as an efficient solution, but just as an easy fix to the buffer-overflow problem (assuming that it's the cause for the issues you are observing).

FileSystemWatcher IncludeSubdirectories not working on network share

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.

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.

Watching log4net log file with FileSystemWatcher

I've created simple WPF control to monitor changes in log file. I used FileSystemWatcher to watch specific file. My configuration:
Directory = System.IO.Path.GetDirectoryName(logFileFullPath);
Filter = System.IO.Path.GetFileName(logFileFullPath);
NotifyFilter = (NotifyFilters.LastWrite | NotifyFilters.Size);
EnableRaisingEvents = true;
The problem is that changes are displayed only after refreshing the directory manually or opening log file.
I use RollingFileAppender in my log4net configuration so changes should be written immediately.
The question is: why dosn't it work and how to make it work?
EDIT :
Also when I update manually other monitored file the watcher works fine. So it must be some log4net issue.
I've finally come up with solution. The problem had little to do with FileSystemWatcher. My log4net configuration was lacking the line:
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
It's still quite interesting as I had no problem with opening log file from text editor.
Try this code,
FileSystemWatcher watcher = new FileSystemWatcher(#"logFileDirectoryPath");
watcher.Filter = "LogFileNameWithExtension";
watcher.EnableRaisingEvents = true;
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
Changed Event
private void watcher_Changed(object sender, FileSystemEventArgs e)
{
//Do Something
}

problem with fileSystemWatcher

I have two applications, CREATOR (which I can't modify) and OBSERVER. CREATOR manipulates many files, and I need OBSERVER to know when that happens. I wrote OBSERVER in C#, and I'm using FileSystemWatcher. I set path to my path, set filter to FILE and add all the necessary events. But when CREATOR modifies the file, no event is raised in OBSERVER. Oddly, when I modify the file by hand, OBSERVER does see the change. I thought that maybe CREATOR doesn't free the file, but when I close CREATOR, OBSERVER still doesn't see the change.
Any idea what I'm doing wrong?
Extra details:
When CREATOR modifies the file, I can delete it by hand, or when I open the file I see that all changes are saved.
edit
my fileSystemWatcher object setting:
fileSystemWatcherObs.EnableRaisingEvents = true;
fileSystemWatcherObs.Filter = "kbd.dbf";
fileSystemWatcherObs.IncludeSubdirectories = true;
fileSystemWatcherObs.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.Attributes |
NotifyFilters.CreationTime | NotifyFilters.DirectoryName |NotifyFilters.LastAccess | NotifyFilters.Security |
NotifyFilters.Size;
fileSystemWatcherObs.Path = "D:\\FOLDER";
fileSystemWatcherObs.SynchronizingObject = this;
fileSystemWatcherObs.Changed += new System.IO.FileSystemEventHandler( this.fileSystemWatcherObs_Changed );
fileSystemWatcherObs.Created += new System.IO.FileSystemEventHandler( this.fileSystemWatcherObs_Created );
fileSystemWatcherObs.Deleted += new System.IO.FileSystemEventHandler( this.fileSystemWatcherObs_Deleted );
fileSystemWatcherObs.Renamed += new System.IO.RenamedEventHandler( this.fileSystemWatcherObs_Renamed );
and of course method for this events
Here a few hints that maybe helps you:
It doesn't matter if you made the changes by hand or by another application "you CREATOR", since when you make them by hand, you actually use some application like "notepad.exe" or something, so that is not really matters.
You should set EnableRaisingEvent to true "start watching" after you set the path and register the event handlers, so the it should be last thing after set all the configurations of the watcher.
At your NotifyFilter are setting the whole notifications filters which will leads you to receive duplicates notifications some times.
Since you only want to watch a specific folder, then you don't have to include sub folders, i.e fIncludeSubdirectories should be false.
Why you are setting a SynchronizingObject to this? a better if you have to anyway is to take it to a new object().

Categories