Added a background file system watcher.
This commit is contained in:
parent
efca1f9c1d
commit
f5e1667368
@ -41,6 +41,8 @@ namespace FileManager
|
|||||||
return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
|
return Directory.CreateDirectory(Configuration.Instance.Books).FullName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BackgroundFileSystem BookDirectoryFiles { get; } = new BackgroundFileSystem();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region instance
|
#region instance
|
||||||
@ -53,7 +55,7 @@ namespace FileManager
|
|||||||
{
|
{
|
||||||
extensions_noDots = Extensions.Select(ext => ext.Trim('.')).ToList();
|
extensions_noDots = Extensions.Select(ext => ext.Trim('.')).ToList();
|
||||||
extAggr = extensions_noDots.Aggregate((a, b) => $"{a}|{b}");
|
extAggr = extensions_noDots.Aggregate((a, b) => $"{a}|{b}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Example for full books:
|
/// Example for full books:
|
||||||
@ -63,16 +65,31 @@ namespace FileManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Exists(string productId) => GetPath(productId) != null;
|
public bool Exists(string productId) => GetPath(productId) != null;
|
||||||
|
|
||||||
public string GetPath(string productId)
|
public string GetPath(string productId)
|
||||||
{
|
{
|
||||||
var cachedFile = FilePathCache.GetPath(productId, FileType);
|
var cachedFile = FilePathCache.GetPath(productId, FileType);
|
||||||
if (cachedFile != null)
|
if (cachedFile != null)
|
||||||
return cachedFile;
|
return cachedFile;
|
||||||
|
|
||||||
var firstOrNull =
|
string storageDir = StorageDirectory;
|
||||||
Directory
|
string regexPattern = $@"{productId}.*?\.({extAggr})$";
|
||||||
.EnumerateFiles(StorageDirectory, "*.*", SearchOption.AllDirectories)
|
string firstOrNull;
|
||||||
.FirstOrDefault(s => Regex.IsMatch(s, $@"{productId}.*?\.({extAggr})$", RegexOptions.IgnoreCase));
|
|
||||||
|
if (storageDir == BooksDirectory)
|
||||||
|
{
|
||||||
|
//If user changed the BooksDirectory, reinitialize.
|
||||||
|
if (storageDir != BookDirectoryFiles.RootDirectory)
|
||||||
|
BookDirectoryFiles.Init(storageDir, "*.*", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
firstOrNull = BookDirectoryFiles.FindFile(regexPattern, RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
firstOrNull =
|
||||||
|
Directory
|
||||||
|
.EnumerateFiles(storageDir, "*.*", SearchOption.AllDirectories)
|
||||||
|
.FirstOrDefault(s => Regex.IsMatch(s, regexPattern, RegexOptions.IgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
if (firstOrNull is null)
|
if (firstOrNull is null)
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
107
FileManager/BackgroundFileSystem.cs
Normal file
107
FileManager/BackgroundFileSystem.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FileManager
|
||||||
|
{
|
||||||
|
class BackgroundFileSystem
|
||||||
|
{
|
||||||
|
public string RootDirectory { get; private set; }
|
||||||
|
public string SearchPattern { get; private set; }
|
||||||
|
public SearchOption SearchOption { get; private set; }
|
||||||
|
|
||||||
|
private FileSystemWatcher fileSystemWatcher { get; set; }
|
||||||
|
private BlockingCollection<FileSystemEventArgs> directoryChangesEvents { get; set; }
|
||||||
|
private Task backgroundScanner { get; set; }
|
||||||
|
private List<string> fsCache { get; set; }
|
||||||
|
|
||||||
|
public string FindFile(string regexPattern, RegexOptions options) =>
|
||||||
|
fsCache.FirstOrDefault(s => Regex.IsMatch(s, regexPattern, options));
|
||||||
|
|
||||||
|
|
||||||
|
public void Init(string rootDirectory, string searchPattern, SearchOption searchOptions)
|
||||||
|
{
|
||||||
|
RootDirectory = rootDirectory;
|
||||||
|
SearchPattern = searchPattern;
|
||||||
|
SearchOption = searchOptions;
|
||||||
|
|
||||||
|
//Calling CompleteAdding() will cause background scanner to terminate.
|
||||||
|
directoryChangesEvents?.CompleteAdding();
|
||||||
|
fsCache?.Clear();
|
||||||
|
directoryChangesEvents?.Dispose();
|
||||||
|
fileSystemWatcher?.Dispose();
|
||||||
|
|
||||||
|
fsCache = Directory.EnumerateFiles(RootDirectory, SearchPattern, SearchOption).ToList();
|
||||||
|
|
||||||
|
directoryChangesEvents = new BlockingCollection<FileSystemEventArgs>();
|
||||||
|
fileSystemWatcher = new FileSystemWatcher(RootDirectory);
|
||||||
|
fileSystemWatcher.Created += FileSystemWatcher_Changed;
|
||||||
|
fileSystemWatcher.Deleted += FileSystemWatcher_Changed;
|
||||||
|
fileSystemWatcher.Renamed += FileSystemWatcher_Changed;
|
||||||
|
fileSystemWatcher.Error += FileSystemWatcher_Error;
|
||||||
|
fileSystemWatcher.IncludeSubdirectories = true;
|
||||||
|
fileSystemWatcher.EnableRaisingEvents = true;
|
||||||
|
|
||||||
|
//Wait for background scanner to terminate before reinitializing.
|
||||||
|
backgroundScanner?.Wait();
|
||||||
|
backgroundScanner = new Task(BackgroundScanner);
|
||||||
|
backgroundScanner.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FileSystemWatcher_Error(object sender, ErrorEventArgs e)
|
||||||
|
{
|
||||||
|
Init(RootDirectory, SearchPattern, SearchOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
|
||||||
|
{
|
||||||
|
directoryChangesEvents.Add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLocalCache(FileSystemEventArgs change)
|
||||||
|
{
|
||||||
|
if (change.ChangeType == WatcherChangeTypes.Deleted)
|
||||||
|
{
|
||||||
|
RemovePath(change.FullPath);
|
||||||
|
}
|
||||||
|
else if (change.ChangeType == WatcherChangeTypes.Created)
|
||||||
|
{
|
||||||
|
AddPath(change.FullPath);
|
||||||
|
}
|
||||||
|
else if (change.ChangeType == WatcherChangeTypes.Renamed)
|
||||||
|
{
|
||||||
|
var renameChange = change as RenamedEventArgs;
|
||||||
|
|
||||||
|
RemovePath(renameChange.OldFullPath);
|
||||||
|
AddPath(renameChange.FullPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemovePath(string path)
|
||||||
|
{
|
||||||
|
var pathsToRemove = fsCache.Where(p => p.StartsWith(path)).ToArray();
|
||||||
|
|
||||||
|
foreach (var p in pathsToRemove)
|
||||||
|
fsCache.Remove(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPath(string path)
|
||||||
|
{
|
||||||
|
if (File.GetAttributes(path).HasFlag(FileAttributes.Directory))
|
||||||
|
fsCache.AddRange(Directory.EnumerateFiles(path, SearchPattern, SearchOption));
|
||||||
|
else
|
||||||
|
fsCache.Add(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BackgroundScanner()
|
||||||
|
{
|
||||||
|
while (directoryChangesEvents.TryTake(out FileSystemEventArgs change, -1))
|
||||||
|
UpdateLocalCache(change);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user