• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

softklin

[Resolvido] Criar uma função de procura de ficheiros que corre numa thread

8 mensagens neste tópico

Boas, estou a fazer uma aplicação que dada uma pasta, procura recursivamente imagens, conta o número de ocorrências e mostra-o ao utilizador (nº ocorrências). O problema é que a se a pasta tiver dimensões razoáveis e várias subpastas, o meu lindo form fica com um fundo branco, sem controlos, ou seja, fica bloqueado por uns segundos.

Ora, eu queria qu isso não acontecesse e em alternativa, fosse mostrada uma simpática mensagem que diz "a procurar ficheiros". Ouvi recentemente falar de threads, e por isso pensei logo em aplicar uma para esta tarefa, mas o problema é que a minha função, por ser recursiva, devolve valores e tem no seu cabeçalho uma variável para ver o caminho:

''' <summary>
''' Verifica quantas imagens estão presentes numa da pasta e suas sub-pastas
''' </summary>
''' <param name="caminho">A pasta a ser analisada</param>
''' <returns>Nº de imagens encontradas (Integer)</returns>
Public Function howMuchPics(ByVal caminho As String)
    Dim fileCount As Integer = 0
    Dim di As New System.IO.DirectoryInfo(caminho)

    ' ficheiros
    For Each file As IO.FileInfo In di.GetFiles
        If file.Extension.ToLower = ".jpg" Or _
           file.Extension.ToLower = ".gif" Or _
           file.Extension.ToLower = ".png" Or _
           file.Extension.ToLower = ".jpeg" Then
            fileCount += 1
        End If
    Next

    ' pastas
    For Each folder As IO.DirectoryInfo In di.GetDirectories
        fileCount += howMuchPics(folder.FullName)
    Next

    Return fileCount
End Function

Pensei em alterar a função para escrever directamente na label, mas queria ver se conseguia fazer código mais reaproveitável. Alguém me pode dar umas dicas de como alterar isto para correr numa thread, visto que não me é possível passar parâmetros nem receber valores? (penso eu, mas corrijam-me se estiver errado)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Nazgulled, até funciona, o meu problema agora é que agora preciso de copiar o resultado, e dá-me um erro que a thread está a tentar aceder a um controlo criado noutra... Tenho de "delegar" a função, e aí volto novamente a perder o parâmetro da função.

jpaulino, porque dizes isso? Para ser sincero nunca testei exaustivamente a função, mas com pastas e subpastas totalizando milhares de fotografias, funcionou. Será por colocar num inteiro e poder passar desse valor? o que sugeres para melhorar? Também já andei no teu blog, mas infelizmente leva-me ao mesmo problema que a solução do Nazgulled me propôs: passar os caminhos.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Se procurares no disco C (todo) dá-te erro porque existem pastas, como o "System Volume Information" que não tens acesso.

No entanto, e caso o BackgroundWorker ou as threads não sirvam para ti, basta colocares um Application.DoEvents() a seguir ao fileCount += 1

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O Application.DoEvents() está a funcionar na perfeição!  :) E obrigado pela dica dos acesso a pastas protegidas pelo SO, como apenas tinha testado em pastas como "As minhas imagens" e do género, nunca me tinha apercebido disso. Talvez ainda adicione um pequeno limite para que o caso de ter de efectuar uma procura muito grande.

Obrigado a ambos pela vossa ajuda, está resolvido!  :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Já agora, outra maneira de fazeres isso, e se não tens problemas nas pastas, é assim:

        Dim jpgFiles() As String = System.IO.Directory.GetFiles("d:\imagens", "*.jpg", IO.SearchOption.AllDirectories)
        Dim bmpFiles() As String = System.IO.Directory.GetFiles("d:\imagens", "*.bmp", IO.SearchOption.AllDirectories)
        Dim gifFiles() As String = System.IO.Directory.GetFiles("d:\imagens", "*.gif", IO.SearchOption.AllDirectories)

        Dim total As Integer = jpgFiles.Length + bmpFiles.Length + gifFiles.Length
        Debug.WriteLine(total)

Mas provavelmente bloqueia-te o form! :)

Experimenta  :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O BackgroundWorker também resolve o teu problema de copiar o resultado. O BackgroundWorker tem alguns eventos próprios para o efeito que te permitem passar objectos de um ado para o outro. Tanto o evento RunWorkerCompleted ou ProgressChanged te permitem aceder a controlos criados na thread "principal". Só o evento onde processas o BackgroundWorker (DoWork) é que não te permite aceder à thread "principal".

Fica aqui um exemplo. Não sei se será melhor ou pior que o teu código actual:

using System;
using System.ComponentModel;
using System.IO;

namespace ConsoleApplication1 {
    public class Program {
        public static void Main(string[] args) {
            Program p = new Program();
            Console.Read();
        }

        private Program() {
            BackgroundWorker bw = new BackgroundWorker();

            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

            bw.RunWorkerAsync();
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
            Console.WriteLine("TOTAL PICS: " + (int)e.Result);
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e) {
            e.Result = howMuchPics("C:\\Users\\Nazgulled\\Pictures");
        }

        private int howMuchPics(string caminho) {
            DirectoryInfo di = new DirectoryInfo(caminho);
            int fileCount = 0;

            try {
                foreach(FileInfo file in di.GetFiles()) {
                    if(file.Extension.ToLower() == ".jpg") {
                        fileCount += 1;
                    }
                }

                foreach(DirectoryInfo folder in di.GetDirectories()) {
                    fileCount += howMuchPics(folder.FullName);
                }
            } catch(UnauthorizedAccessException ex) {
                Console.WriteLine("EXCEPTION: " + ex.Message + "\n");
            }

            return fileCount;
        }
    }
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora