FileSystemWatcher - как отследить копирование папки с файлами? - C#
Формулировка задачи:
Не понимаю как отследить копирование или перемещение папки с файлами. Отслеживание создания отдельно файлов или отдельно папки работает замечательно. А вот если в отслеживаемую директорию скопировать или переместить папку с файлами, то FileSystemWatcher сообщит только о создании папки. MSDN говорит по этому поводу:
Но Renamed и Changed происходят только если переименовывать файл в уже существующей папке в отслеживаемой директории. Если же в отслеживаемую директорию копировать или перемещать папку с файлами, то Renamed и Changed не происходят, а происходит только Created и сообщает о создании только папки без файлов в ней.
Как решить подобную проблему?
"ОС и объект FileSystemWatcher интерпретируют действие вырезания и вставки или действие перемещения как действие переименования для папки и ее содержимого. Если вы вырезаете и вставляете папку с файлами в отслеживаемую папку, объект FileSystemWatcher сообщает как о новой только о папке, но не о ее содержимом, так как оно фактически было только переименовано. Чтобы получить уведомление о том, что содержимое папок было перемещено или скопировано в отслеживаемую папку, используйте методы обработчика событий OnChanged и OnRenamed..."
Решение задачи: «FileSystemWatcher - как отследить копирование папки с файлами?»
textual
Листинг программы
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Timers;
namespace Test
{
public class Service
{
private FileSystemWatcher watcher;
private volatile bool enabled = true;
private List<string> fileAndFolderList;
private System.Timers.Timer timer;
public Service()
{
watcher = new FileSystemWatcher( this.aesSource );
watcher.IncludeSubdirectories = true;
watcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName;
watcher.Created += new FileSystemEventHandler( Watcher_Created );
fileAndFolderList = new List<string>();
timer = new System.Timers.Timer();
timer.Interval = 3000;
timer.AutoReset = false;
timer.Elapsed += Timer_Elapsed;
}
public void OnStart()
{
Thread serviceThread = new Thread( new ThreadStart( this.Start ) );
serviceThread.Name = "TestService";
serviceThread.Start();
}
private void Start()
{
watcher.EnableRaisingEvents = true;
while ( enabled )
{
Thread.Sleep( 100 );
}
}
public void OnStop()
{
this.Stop();
Thread.Sleep( 1000 );
}
private void Stop()
{
watcher.EnableRaisingEvents = false;
enabled = false;
}
private void Watcher_Created( object sender, FileSystemEventArgs e )
{
lock ( this )
{
fileAndFolderList.Add( e.FullPath );
}
if ( PathIsDirectory( e.FullPath ) )
{
timer.Enabled = false;
Thread.Sleep( 100 );
timer.Enabled = true;
}
else
{
WaitForFileCopy( e.FullPath );
}
}
private void Timer_Elapsed( Object source, ElapsedEventArgs e )
{
lock ( this )
{
foreach ( var item in fileAndFolderList )
{
if ( PathIsDirectory( item ) )
{
TraverseTree( item );
}
else
{
RecordEntry( item );
}
}
fileAndFolderList.Clear();
}
}
private void RecordEntry( string filePath )
{
try
{
lock ( this )
{
using ( StreamWriter writer = new StreamWriter( @"D:\Delete\templog.txt", true ) )
{
writer.WriteLine( filePath );
writer.Flush();
}
}
}
catch
{
throw new ArgumentException();
}
}
private void TraverseTree( string pathToFolder )
{
//https://msdn.microsoft.com/ru-ru/library/bb513869.aspx
// Data structure to hold names of subfolders to be
// examined for files.
Stack<string> dirs = new Stack<string>();
if ( !System.IO.Directory.Exists( pathToFolder ) )
{
throw new ArgumentException();
}
dirs.Push( pathToFolder );
while ( dirs.Count > 0 )
{
string currentDir = dirs.Pop();
string[] subDirs;
try
{
subDirs = System.IO.Directory.GetDirectories( currentDir );
}
// An UnauthorizedAccessException exception will be thrown if we do not have
// discovery permission on a folder or file. It may or may not be acceptable
// to ignore the exception and continue enumerating the remaining files and
// folders. It is also possible (but unlikely) that a DirectoryNotFound exception
// will be raised. This will happen if currentDir has been deleted by
// another application or thread after our call to Directory.Exists. The
// choice of which exceptions to catch depends entirely on the specific task
// you are intending to perform and also on how much you know with certainty
// about the systems on which this code will run.
catch ( UnauthorizedAccessException e )
{
Console.WriteLine( e.Message );
continue;
}
catch ( System.IO.DirectoryNotFoundException e )
{
Console.WriteLine( e.Message );
continue;
}
string[] files = null;
try
{
files = System.IO.Directory.GetFiles( currentDir );
}
catch ( UnauthorizedAccessException e )
{
Console.WriteLine( e.Message );
continue;
}
catch ( System.IO.DirectoryNotFoundException e )
{
Console.WriteLine( e.Message );
continue;
}
// Perform the required action on each file here.
// Modify this block to perform your required task.
foreach ( string file in files )
{
try
{
// Perform whatever action is required in your scenario.
System.IO.FileInfo fi = new System.IO.FileInfo( file );
if ( !fileAndFolderList.Contains( fi.FullName ) )
{
RecordEntry( fi.FullName );
}
}
catch ( System.IO.FileNotFoundException e )
{
// If file was deleted by a separate application
// or thread since the call to TraverseTree()
// then just continue.
Console.WriteLine( e.Message );
continue;
}
}
// Push the subdirectories onto the stack for traversal.
// This could also be done before handing the files.
foreach ( string str in subDirs )
dirs.Push( str );
}
}
private void WaitForFileCopy( string fileName )
{
//https://social.msdn.microsoft.com/Forums/vstudio/en-US/5695490c-a644-48a3-be2b-cfb762cf4765/filesystemwatcher-has-to-wait-until-file-is-fully-written?forum=netfxbcl
while ( true )
{
try
{
lock ( this )
{
using ( StreamReader stream = new StreamReader( fileName ) )
{
timer.Enabled = true;
break;
}
}
}
catch
{
timer.Enabled = false;
Thread.Sleep( 100 );
}
}
}
private bool PathIsDirectory( string path )
{
return ( Directory.Exists( path ) ) ? true : false;
}