using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using FileIO = System.IO.File; using DirectoryIO = System.IO.Directory; using CodeStatistics.Input.Methods; using CodeStatistics.Forms; using CodeStatisticsCore.Input; namespace CodeStatistics.Input{ class FileSearch : IInputMethod{ public delegate void RefreshEventHandler(int entriesFound); public delegate void FinishEventHandler(FileSearchData searchData); public delegate void FailureEventHandler(Exception ex); public event RefreshEventHandler Refresh; public event FinishEventHandler Finish; public event FailureEventHandler Failure; private event Action CancelFinish; private readonly string[] rootFiles; private readonly CancellationTokenSource cancelToken; public FileSearch(string[] files){ this.rootFiles = files; cancelToken = new CancellationTokenSource(); } public void StartAsync(){ var task = new Task(() => { var searchData = new FileSearchData(rootFiles.Length == 0 ? string.Empty : IOUtils.FindRootPath(rootFiles)); var rand = new Random(); int[] entryCount = { 0 }; int nextNotice = 0; Action updateNotice = () => { if (--nextNotice < 0){ if (Refresh != null)Refresh(entryCount[0]); nextNotice = 100+rand.Next(50); } }; updateNotice(); foreach(string rootFile in rootFiles){ if (cancelToken.IsCancellationRequested){ if (CancelFinish != null)CancelFinish(); return; } bool? isDirectory = IOUtils.IsDirectory(rootFile); if (!isDirectory.HasValue)continue; if (isDirectory.Value){ foreach(IOEntry entry in EnumerateEntriesSafe(rootFile)){ if (cancelToken.IsCancellationRequested){ if (CancelFinish != null)CancelFinish(); return; } searchData.Add(entry); ++entryCount[0]; updateNotice(); } } else{ searchData.Add(new IOEntry(IOEntry.Type.File,rootFile)); ++entryCount[0]; updateNotice(); } } if (Refresh != null)Refresh(entryCount[0]); if (Finish != null)Finish(searchData); },cancelToken.Token); task.ContinueWith(originalTask => { if (Failure != null)Failure(originalTask.Exception); },TaskContinuationOptions.OnlyOnFaulted); task.Start(); } private static IEnumerable<IOEntry> EnumerateEntriesSafe(string path){ var foldersLeft = new Queue<string>(64); foldersLeft.Enqueue(path); while(foldersLeft.Count > 0){ string currentFolder = foldersLeft.Dequeue(); string[] files, folders; try{ files = DirectoryIO.GetFiles(currentFolder,"*.*",SearchOption.TopDirectoryOnly); }catch(Exception){ files = new string[0]; } try{ folders = DirectoryIO.GetDirectories(currentFolder,"*.*",SearchOption.TopDirectoryOnly); }catch(Exception){ folders = new string[0]; } foreach(string file in files){ yield return new IOEntry(IOEntry.Type.File,file); } foreach(string folder in folders){ foldersLeft.Enqueue(folder); yield return new IOEntry(IOEntry.Type.Folder,folder); } } } public void BeginProcess(ProjectLoadForm.UpdateCallbacks callbacks){ callbacks.OnReady(this); } public void CancelProcess(Action onCancelFinish){ cancelToken.Cancel(false); CancelFinish += onCancelFinish; } } }