.Net: Classe para pesquisa de arquivos assíncrona e com múltiplos filtros – C#

Olá Pessoal,

Esse é o meu último dia de férias do trabalho (choro eterno), e acabei escrevendo um código para uma contribuição no MSDN que achei que seria interessante publicar.

É uma classe para pesquisa de arquivos assíncrona e que permite o uso de múltiplos filtros (de forma simultânea, na qual só serão retornados os resultados que satisfizerem a todos os filtros, de forma normal, onde serão retornados os arquivos que atendem a qualquer um dos filtros, mesmo que só um).

É um código simples, mas que na pressa, vale um Ctrl + C Ctrl + V. Enfim, segue o código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;

namespace HL.IO
{
    public class FileSearch
    {
        private string[] _Filters;
        public string[] Filters
        {
            get { return _Filters; }
            set { _Filters = value; }
        }

        private SearchOptions _SearchOption;
        public SearchOptions SearchOption
        {
            get { return _SearchOption; }
            set { _SearchOption = value; }
        }

        public FileSearch(SearchOptions SearchOption, params string[] Filters)
        {
            _Filters = Filters;
            _SearchOption = SearchOption;
        }
        public FileSearch()
        {
            _SearchOption = SearchOptions.AllDirectories | SearchOptions.MatchAllFilters;
            _Filters = null;
        }
        public IEnumerable<string> Search(string RootFolder)
        {
            if (_SearchOption.HasFlag(SearchOptions.AllDirectories))
            {
                IEnumerable<string> result = Directory.EnumerateFiles(RootFolder, "*.*", System.IO.SearchOption.AllDirectories);
                if (_SearchOption.HasFlag(SearchOptions.MatchAllFilters))
                    return result.Where(s => Path.GetFileName(s).ContainsAll(_Filters,
                        _SearchOption.HasFlag(SearchOptions.CaseSensitive)));
                else
                    return result.Where(s => Path.GetFileName(s).ContainsAny(_Filters,
                        _SearchOption.HasFlag(SearchOptions.CaseSensitive)));
            }
            else
            {
                IEnumerable<string> result = Directory.EnumerateFiles(RootFolder, "*.*", System.IO.SearchOption.TopDirectoryOnly);
                if (_SearchOption.HasFlag(SearchOptions.MatchAllFilters))
                    return result.Where(s => Path.GetFileName(s).ContainsAll(_Filters,
                        _SearchOption.HasFlag(SearchOptions.CaseSensitive)));
                else
                    return result.Where(s => Path.GetFileName(s).ContainsAny(_Filters,
                        _SearchOption.HasFlag(SearchOptions.CaseSensitive)));
            }
        }

        #region Async
        public void AsyncSearch(string RootFolder)
        {
            SynchronizationContext context = SynchronizationContext.Current;
            if (context == null)
            {
                context = new System.Threading.SynchronizationContext();
            }
            Thread th = new Thread(new ThreadStart(() =>
            {
                IEnumerable<string> result = Search(RootFolder);
                context.Send(new SendOrPostCallback((object state) =>
                {
                    OnAsyncSearchCompleted((IEnumerable<string>)state);
                }), result);
            }));
            th.IsBackground = false;
            th.SetApartmentState(ApartmentState.STA);
            th.Start();
        }
        public event AsyncSearchCompletedEventHandler AsyncSearchCompleted;
        protected virtual void OnAsyncSearchCompleted(IEnumerable<string> Result)
        {
            if (AsyncSearchCompleted != null)
            {
                AsyncSearchCompleted(this, new AsyncSearchCompletedEventArgs(Result));
            }
        }
        #endregion
    }

    public delegate void AsyncSearchCompletedEventHandler(object sender, AsyncSearchCompletedEventArgs e);

    public class AsyncSearchCompletedEventArgs
    {
        private IEnumerable<string> _result;
        public IEnumerable<string> Result
        {
            get { return _result; }
        }
        public AsyncSearchCompletedEventArgs(IEnumerable<string> Result)
        {
            _result = Result;
        }
    }
    public enum SearchOptions : int
    {
        /// <summary>
        /// The search engine will seach only on top level of the given root folder.
        /// </summary>
        TopDirectoryOnly = 1,
        /// <summary>
        /// The search engine will search in all the directory tree starting from the given root folder
        /// </summary>
        AllDirectories = 2,
        /// <summary>
        /// The search engine will use case sensitive approach.
        /// </summary>
        CaseSensitive = 4,
        /// <summary>
        /// If set, the search engine will return only the results matching all the filters.
        /// </summary>
        MatchAllFilters = 8
    };
    public static class StringExtensions
    {
        public static bool ContainsAll(this string Source, string[] strs, bool CaseSensitive)
        {
            foreach (string str in strs)
            {
                if (CaseSensitive)
                {
                    if (!Source.Contains(str)) return false;
                }
                else
                {
                    if (!Source.ToLower().Contains(str.ToLower())) return false;
                }
            }
            return true;
        }

        public static bool ContainsAny(this string Source, string[] strs, bool CaseSensitive)
        {
            foreach (string str in strs)
            {
                if (CaseSensitive)
                {
                    if (Source.Contains(str)) return true;
                }
                else
                {
                    if (Source.ToLower().Contains(str.ToLower())) return true;
                }
            }
            return false;
        }
    }
}

Mostrarei também um pequeno exemplo:

        private void btnSearch_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            dialog.ShowDialog();
            FileSearch searcher = new FileSearch(SearchOptions.AllDirectories, ".png", ".bmp", ".jpeg");
            searcher.AsyncSearchCompleted += searcher_AsyncSearchCompleted;
            searcher.AsyncSearch(dialog.SelectedPath);
        }

        private void searcher_AsyncSearchCompleted(object sender, AsyncSearchCompletedEventArgs e)
        {
            listBox1.Items.Clear();
            listBox1.Items.AddRange(e.Result.ToArray());
        }

No exemplo acima a classe FileSearch é usada para encontrar todos os arquivos PNG, BMP e JPEG da pasta informada. Isso é bem básico, mas dá para fazer bastante coisa. Incluir uma palavra chave que o nome do arquivo deve conter também é uma opção. E o melhor de tudo, assíncrono. Não irá congelar a interface de usuário enquanto realiza a busca.

That’s all folks!!!

Anúncios

Deixe um comentário :)

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s