Browse Source

Finished

master
gper2k 2 weeks ago
parent
commit
dd6dc6e772
  1. 15
      BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/DirectoryFileEventArgs.cs
  2. 123
      BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/DirectoryWatcher.cs
  3. 9
      BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/EventMode.cs
  4. 23
      BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.deps.json
  5. BIN
      BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.dll
  6. BIN
      BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.pdb
  7. 31
      BitPlus.IO.Directory.Watcher/Sampl/Program.cs
  8. BIN
      BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.dll
  9. BIN
      BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.pdb
  10. 39
      BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.deps.json
  11. BIN
      BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.dll
  12. BIN
      BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.exe
  13. BIN
      BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.pdb
  14. 12
      BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.runtimeconfig.json
  15. 2
      README.md
  16. BIN
      sample.png

15
BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/DirectoryFileEventArgs.cs

@ -0,0 +1,15 @@
namespace BitPlus.IO.Directory.Watcher;
public sealed class DirectoryFileEventArgs : EventArgs
{
public string FullPath { get; }
public EventMode Mode { get; }
public string? OldFullPath { get; }
public DirectoryFileEventArgs(string fullPath, EventMode mode, string? oldFullPath = null)
{
this.FullPath = fullPath;
this.Mode = mode;
this.OldFullPath = oldFullPath;
}
}

123
BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/DirectoryWatcher.cs

@ -1,6 +1,125 @@
namespace BitPlus.IO.Directory.Watcher; using System.Collections.Concurrent;
using Dir = System.IO.Directory;
public class DirectoryWatcher namespace BitPlus.IO.Directory.Watcher;
public sealed class DirectoryWatcher : IDisposable
{
private readonly FileSystemWatcher _watcher;
private readonly ConcurrentDictionary<string, DateTimeOffset> _lastEventTimes = new();
private readonly TimeSpan _dedupeWindow = TimeSpan.FromMilliseconds(200);
private bool _disposed;
public string TargetDirectory { get; }
public bool IncludeSubdirectories
{
get => this._watcher.IncludeSubdirectories;
set => this._watcher.IncludeSubdirectories = value;
}
public event EventHandler<DirectoryFileEventArgs>? FileCreated;
public event EventHandler<DirectoryFileEventArgs>? FileChanged;
public event EventHandler<DirectoryFileEventArgs>? FileDeleted;
public event EventHandler<DirectoryFileEventArgs>? FileRenamed;
public event EventHandler<ErrorEventArgs>? WatcherError;
public DirectoryWatcher(string targetDirectory, string filter = "*.*")
{
if (string.IsNullOrWhiteSpace(targetDirectory))
throw new ArgumentException("Target directory cannot be empty.", nameof(targetDirectory));
if (!Dir.Exists(targetDirectory))
throw new DirectoryNotFoundException(targetDirectory);
this.TargetDirectory = targetDirectory;
this._watcher = new FileSystemWatcher(this.TargetDirectory, filter)
{
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime,
IncludeSubdirectories = false,
EnableRaisingEvents = false
};
this._watcher.Created += this.OnCreated;
this._watcher.Changed += this.OnChanged;
this._watcher.Deleted += this.OnDeleted;
this._watcher.Renamed += this.OnRenamed;
this._watcher.Error += this.OnError;
}
public void Start()
{
this.ThrowIfDisposed();
this._watcher.EnableRaisingEvents = true;
}
public void Stop()
{ {
this.ThrowIfDisposed();
this._watcher.EnableRaisingEvents = false;
}
private void OnCreated(object? sender, FileSystemEventArgs e)
{
if (this.ShouldRaise(e.FullPath))
FileCreated?.Invoke(this, new DirectoryFileEventArgs(e.FullPath, EventMode.Created));
}
private void OnChanged(object? sender, FileSystemEventArgs e)
{
if (this.ShouldRaise(e.FullPath))
FileChanged?.Invoke(this, new DirectoryFileEventArgs(e.FullPath, EventMode.Changed));
}
private void OnDeleted(object? sender, FileSystemEventArgs e)
{
if (this.ShouldRaise(e.FullPath))
FileDeleted?.Invoke(this, new DirectoryFileEventArgs(e.FullPath, EventMode.Deleted));
}
private void OnRenamed(object? sender, RenamedEventArgs e)
{
if (this.ShouldRaise(e.FullPath))
{
var args = new DirectoryFileEventArgs(e.FullPath, EventMode.Renamed, e.OldFullPath);
FileChanged?.Invoke(this, args);
FileRenamed?.Invoke(this, args);
}
}
private void OnError(object? sender, ErrorEventArgs e)
=> WatcherError?.Invoke(this, e);
private bool ShouldRaise(string fullPath)
{
var now = DateTimeOffset.UtcNow;
if (this._lastEventTimes.TryGetValue(fullPath, out var last))
{
if (now - last < this._dedupeWindow)
return false;
}
this._lastEventTimes[fullPath] = now;
return true;
}
private void ThrowIfDisposed()
{
if (this._disposed)
throw new ObjectDisposedException(nameof(DirectoryWatcher));
}
public void Dispose()
{
if (this._disposed) return;
this._disposed = true;
this._watcher.Created -= this.OnCreated;
this._watcher.Changed -= this.OnChanged;
this._watcher.Deleted -= this.OnDeleted;
this._watcher.Renamed -= this.OnRenamed;
this._watcher.Error -= this.OnError;
this._watcher.Dispose();
}
} }

9
BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/EventMode.cs

@ -0,0 +1,9 @@
namespace BitPlus.IO.Directory.Watcher;
public enum EventMode
{
Created,
Changed,
Deleted,
Renamed
}

23
BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.deps.json

@ -0,0 +1,23 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v10.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v10.0": {
"BitPlus.IO.Directory.Watcher/1.0.0": {
"runtime": {
"BitPlus.IO.Directory.Watcher.dll": {}
}
}
}
},
"libraries": {
"BitPlus.IO.Directory.Watcher/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

BIN
BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.dll

Binary file not shown.

BIN
BitPlus.IO.Directory.Watcher/BitPlus.IO.Directory.Watcher/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.pdb

Binary file not shown.

31
BitPlus.IO.Directory.Watcher/Sampl/Program.cs

@ -1,7 +1,34 @@
internal class Program using BitPlus.IO.Directory.Watcher;
internal class Program
{ {
private static void Main(string[] args) private static void Main(string[] args)
{ {
Console.WriteLine("Hello, World!"); var path = args.Length > 0 ? args[0] : null;
while (string.IsNullOrWhiteSpace(path) || !Directory.Exists(path))
{
Console.Write("감시할 폴더 경로를 입력하세요(Enter the folder path to monitor.): ");
path = Console.ReadLine();
if (string.IsNullOrWhiteSpace(path))
Console.WriteLine("경로가 비어 있습니다.(The path is empty.)");
else if (!Directory.Exists(path))
Console.WriteLine("폴더가 존재하지 않습니다.(The folder does not exist.)");
}
using var watcher = new DirectoryWatcher(path);
watcher.FileCreated += (_, e) => Console.WriteLine($"[CREATE] {e.FullPath}");
watcher.FileChanged += (_, e) => Console.WriteLine($"[CHANGE] {e.FullPath}");
watcher.FileDeleted += (_, e) => Console.WriteLine($"[DELETE] {e.FullPath}");
watcher.FileRenamed += (_, e) => Console.WriteLine($"[RENAME] {e.OldFullPath} -> {e.FullPath}");
watcher.WatcherError += (_, e) => Console.WriteLine($"[ERROR] {e.GetException().Message}");
watcher.Start();
Console.WriteLine($"감시 시작(Start the surveillance): {path}");
Console.WriteLine("종료하려면 Enter를 누르세요...(Press Enter to exit)");
Console.ReadLine();
watcher.Stop();
} }
} }

BIN
BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.dll

Binary file not shown.

BIN
BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/BitPlus.IO.Directory.Watcher.pdb

Binary file not shown.

39
BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.deps.json

@ -0,0 +1,39 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v10.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v10.0": {
"Sample/1.0.0": {
"dependencies": {
"BitPlus.IO.Directory.Watcher": "1.0.0"
},
"runtime": {
"Sample.dll": {}
}
},
"BitPlus.IO.Directory.Watcher/1.0.0": {
"runtime": {
"BitPlus.IO.Directory.Watcher.dll": {
"assemblyVersion": "1.0.0.0",
"fileVersion": "1.0.0.0"
}
}
}
}
},
"libraries": {
"Sample/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"BitPlus.IO.Directory.Watcher/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

BIN
BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.dll

Binary file not shown.

BIN
BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.exe

Binary file not shown.

BIN
BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.pdb

Binary file not shown.

12
BitPlus.IO.Directory.Watcher/Sampl/bin/Debug/net10.0/Sample.runtimeconfig.json

@ -0,0 +1,12 @@
{
"runtimeOptions": {
"tfm": "net10.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "10.0.0"
},
"configProperties": {
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}

2
README.md

@ -2,3 +2,5 @@
디렉터리를 감시 및 변경에 따른 이벤트 처리기 디렉터리를 감시 및 변경에 따른 이벤트 처리기
Event handlers for monitoring and changing directories Event handlers for monitoring and changing directories
![sample](./sample.png)

BIN
sample.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Loading…
Cancel
Save