FileSystemWatcher on Linux #69700
Replies: 2 comments 3 replies
-
By using the PhysicalFileProvider we are able to get most of what we are needing, in our case we needed to know when new files were added to the disk and send them to a queue. The code below achieves this for us and may be of use for others. using FileStreamClient.Queues;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
namespace Project.Services
{
private readonly ILogger<FileMonitor> _logger;
private readonly IFileTransferQueue _fileTransferQueue;
private readonly IServiceProvider _serviceProvider;
private readonly IConfiguration _configuration;
private readonly string _directoryToMonitor;
private readonly List<string> _fileTypes;
private FileSystemWatcher _fileSystemWatcher;
private static PhysicalFileProvider _fileProvider;
private static IChangeToken _fileChangeToken;
private Dictionary<string, DateTime> _previousStateOfFiles = new();
public class FileMonitor
{
public FileMonitor(ILogger<FileMonitor> logger, IServiceProvider serviceProvider, IConfiguration configuration)
{
_logger = logger;
_serviceProvider = serviceProvider;
_configuration = configuration;
_fileTransferQueue = _serviceProvider.GetService<IFileTransferQueue>();
_directoryToMonitor = _configuration.GetValue<string>("DirectoryToMonitor");
_fileTypes = _configuration.GetSection("FileTypes").Get<List<string>>();
for (int i = 0; i < _fileTypes.Count; i++)
{
_fileTypes[i] = _fileTypes[i].Replace("*", "");
}
StartMonitoringPhysicalDirectory();
}
private void StartMonitoringPhysicalDirectory()
{
_fileProvider = new PhysicalFileProvider(_directoryToMonitor);
WatchForFileChanges();
}
private void Notify(object state)
{
WatchForFileChanges();
}
private void WatchForFileChanges()
{
ConcurrentDictionary<string, DateTime> currentStateOfFiles = new();
IEnumerable<string> currentFiles= Directory.EnumerateFiles(_directoryToMonitor, "*.*", SearchOption.AllDirectories);
foreach (string file in currentFiles)
{
// This will be either OnCreated, OnChanged, OnRenamed
if (File.Exists(file))
{
if (_previousStateOfFiles.TryGetValue(file, out DateTime previousWriteTime))
{
var currentWriteTime = File.GetLastWriteTime(file);
if (previousWriteTime == currentWriteTime)
{
// file has not been changed. It is being found again.
currentStateOfFiles.TryAdd(file, currentWriteTime);
}
else
{
// file has been Changed
currentStateOfFiles.TryAdd(file, currentWriteTime);
// OnChanged(file);
}
}
else
{
// file has been created or renamed
currentStateOfFiles.TryAdd(file, File.GetLastWriteTime(file));
OnCreated(file);
}
}
else
{
_logger.LogTrace($"{file }has been deleted");
// OnDeleted();
}
}
_fileChangeToken = _fileProvider.Watch("**/*.*");
_fileChangeToken.RegisterChangeCallback(Notify, default);
_previousStateOfFiles = currentStateOfFiles;
}
private void MonitorDirectory(string directoryToMonitor)
{
try
{
_logger.LogInformation(directoryToMonitor);
_fileSystemWatcher = new FileSystemWatcher(directoryToMonitor, "*");
_fileSystemWatcher.Created += OnCreated;
_fileSystemWatcher.Renamed += OnRenamed;
_fileSystemWatcher.IncludeSubdirectories = true;
_fileSystemWatcher.EnableRaisingEvents = true;
}
catch (Exception e)
{
_logger.LogError($"{e}");
}
}
private void OnCreated(object sender, FileSystemEventArgs e)
{
var fullPath = e.FullPath;
OnCreated(fullPath);
}
private void OnCreated(string fullPath)
{
if (Directory.Exists(fullPath))
{
return;
}
else
{
if (_fileTypes.Any<string>(fullPath.Contains))
{
_fileTransferQueue.AddToTransferToCoordinator(fullPath);
_logger.LogTrace($"Added {fullPath} to the queue");
}
}
} This also had a by product of grabbing all the existing files from disk as well. |
Beta Was this translation helpful? Give feedback.
-
I am trying to implement a FileSystemWatcher in a .NET 8 C# console application and its not working when used on Linux (works great on Windows). Was curious if anyone knows what might be the issue. Has this issue been resolved or might be resolved in the upcoming releases of .NET? |
Beta Was this translation helpful? Give feedback.
-
Hello,
I have the following scenario that works on Windows in dotnet 6.0:
C:/Monitor
C:/Monitor/Folder A
, (a number of files are already present in this directory and no additional ones will be added)Folder A
added to the queue (separate thread)C:/Monitor/Folder B
Folder B
This works as expected with the following code:
How ever if we deploy this code to Ubuntu 20.04
/data/Monitor
/data/Monitor/Folder A
(a number of files are already present in this directory and no additional ones will be added)Folder A
added to the queue (separate thread)/data/Monitor/Folder B
Folder B
We do not see the files created or changed being added to the queue. Under the hood it looks like dotnet is using inotify which is what the python version of the above code was also using (watchdog uses inotify as well). The python version of the code will detect the newly created files and add them to the queue.
Any ideas on how I could debug this to figure out why the C# code is not detecting the files being added.
Beta Was this translation helpful? Give feedback.
All reactions