none
Visualizzazione ricerca file in Label RRS feed

  • Domanda

  • Salve a tutti

    nella creazione del mio progetto ( Windows form, vb10 ) ho bisogno di cercare un file ( es. test.txt ) nel pc dove verra installata l'applicazione

    ed eseguo questo codice


     For Each foundFile As String In My.Computer.FileSystem.GetFiles( _
       My.Computer.FileSystem.SpecialDirectories.Desktop, _
       FileIO.SearchOption.SearchAllSubDirectories, "test.txt")

               
                Label3.Text = foundFile

            Next


    e vorrei chiedere

    1) come faccio ad effettuare la ricerca su tutto il pc ( C:\) e non solo in desktop

    2) vorrei che il Label3.Text mi motrasse tutte le cartelle che scansiona man mano ( e non alla fine dove e' presente il file )


    Speroi di essere stato chiaro

    Grazie a tutti
    lunedì 1 agosto 2011 18:36

Risposte

  • Il metodo GetFiles che utilizzi tu esegue già una ricerca ricorsiva dei file, il problema è che potresti andare a leggere delle cartelle per cui non hai i privilegi e, allora, beccheresti un errore di accesso che vanificherebbe l'intera ricerca (è, probabilmente, quello che accade se fai la ricerca su tutto C:). Devi implementare una ricerca ricorsiva come ti ha suggerito Matteo ma mi permetto di inserirci una gestione delle eventuali eccezioni di accesso a cartelle (altrimenti ti ritrovi da capo):

       Public Function GetFilesRecursive(rootPath As String, wildcard As String,
    ByVal logger As ILogger) As IEnumerable(Of String)
           If logger Is Nothing Then Throw New ArgumentNullException()
           Dim list = New List(Of String)
           Try
               list.AddRange(System.IO.Directory.GetFiles(rootPath, wildcard))
               For Each dirPath In System.IO.Directory.GetDirectories(rootPath)
                   logger.Debug(dirPath)
                   list.AddRange(GetFilesRecursive(dirPath, wildcard, logger))
               Next
           Catch ex As Exception
            End Try
           Return list
       End Function

    Volendo potresti eseguire un controllo sui privilegi di accesso alla directory prima di richiederne i file, ma il codice scritto è il minimo indispensabile.

    Come dice Matteo, crei una classe che implementa ILogger e scrivi ovunque tu voglia.
    Il problema è che se metti questo codice nel thread principale della form (ad esempio nel click di un bottone) non vedrai mai nulla perchè la funzione occupa il thread principale che si occupa anche del refresh dell'interfaccia.
    Per questo motivo (un'operazione lunga potrebbe freezare l'interfaccia) ti consiglio di mettere la funzione in un thread separato.
    Potresti utilizzare la classe Task (per maggiori info guarda su MSDN o http://codetailor.blogspot.com/2010/10/i-tasks-del-net-framework-40.html). Nel seguente esempio lancio la ricerca dei file al load della form (ma non mi curo dei risultati che magari a te servono):

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles
    MyBase.Load
       Dim task = New Threading.Tasks.Task(Sub() GetFilesThreadCode())
       task.Start()
    End Sub
    
    Private Sub GetFilesThreadCode()
       Dim logger = New TextBoxLogger(Me.TextBox1)
       Dim files = GetFilesRecursive("c:\", "*.txt", logger)
    End Sub

    dove TextBoxLogger è la suddetta classe che implementa ILogger di Matteo:

    Public Class TextBoxLogger
       Implements ILogger
        Private _Textbox As TextBox
       Public Sub New(textBox As TextBox)
           If textBox Is Nothing Then Throw New ArgumentNullException
           _Textbox = textBox
       End Sub
        Public Sub Debug(message As String) Implements ILogger.Debug
           _Textbox.Text = message
       End Sub
    End Class

    A questo punto non blocchi l'interfaccia ma vedrai che la funzione di recupero dei file va in eccezione, questo capita perchè stai tentando di modificare la UI da un thread che non è quello proprietario della stessa e, questo, poichè le applicazioni .NEt sono STA (Single Thread Apartment) non si pèuò fare. Per risolvere il problema devi eseguire la visualizzazione impersonando il thread principale e per fare questo puoi usare la tecnica dell'Invoke (http://www.domusdotnet.org/pillole/20110701-aggiornare-controlli-da-thread-secondari-con-invoke.aspx):

    Public Class TextBoxLogger
       Implements ILogger
        Private _Textbox As TextBox
       Public Sub New(textBox As TextBox)
           If textBox Is Nothing Then Throw New ArgumentNullException
           _Textbox = textBox
       End Sub
        Public Sub Debug(message As String) Implements ILogger.Debug
           UpdateTextbox(message)
       End Sub
        Private Delegate Sub UpdateTextBoxDelegate(message As String)
        Private Sub UpdateTextbox(message As String)
           If Me._Textbox.InvokeRequired Then
               Me._Textbox.BeginInvoke(New UpdateTextBoxDelegate(AddressOf UpdateTextbox),
    {message})
           Else
               _Textbox.Text = message
           End If
       End Sub
    End Class

    Spero di essere stato chiaro (anche se non esaustivo).

    • Proposto come risposta Irina Turcu mercoledì 10 agosto 2011 15:28
    • Contrassegnato come risposta Irina Turcu martedì 16 agosto 2011 08:08
    martedì 2 agosto 2011 06:56
    Moderatore
  • E' stata una scelta volontaria quella di visualizzare solo il path della directory che sta esaminando, altrimenti avrei creato un log che, anzichè lavorare su un TextBox, deve lavorare su una ListBox, tipo il seguente:

    Public Class ListBoxLogger
       Implements ILogger
        Private _Listbox As ListBox
       Public Sub New(listBox As ListBox)
           If listBox Is Nothing Then Throw New ArgumentNullException
           _Listbox = listBox
       End Sub
        Public Sub Debug(message As String) Implements ILogger.Debug
           UpdateListbox(message)
       End Sub
        Private Delegate Sub UpdateListboxDelegate(message As String)
        Private Sub UpdateListbox(message As String)
           If Me._Listbox.InvokeRequired Then
               Me._Listbox.BeginInvoke(New UpdateListboxDelegate(AddressOf UpdateListbox),
    {message})
           Else
               _Listbox.Items.Insert(0, message)
           End If
       End Sub
    End Class

    Per quanto riguarda la gestione degli errori, neanche io la metto di solito, ma stavolta serviva. La funzione usata in origine già fa la ricerca recursiva ma ha il problema di andare in errore quando si va a leggere una cartella di cui non si hanno gli opportuni diritti.

    Il mio intervento non aveva nulla di critico nei tuoi confronti (scusami se ti ho dato questa impressione) voleva solo dettagliare meglio la soluzione proposta.

    • Proposto come risposta Irina Turcu mercoledì 10 agosto 2011 15:28
    • Contrassegnato come risposta Irina Turcu martedì 16 agosto 2011 08:08
    martedì 2 agosto 2011 08:12
    Moderatore
    • Proposto come risposta Irina Turcu mercoledì 10 agosto 2011 15:27
    • Contrassegnato come risposta Irina Turcu martedì 16 agosto 2011 08:08
    martedì 2 agosto 2011 22:14
  • Ho pubblicato qui l'applicazione che cicla sulle directory:
    http://sample.codeplex.com/SourceControl/changeset/view/61129#1224949

    Mentre qui trovi l'applicazione che permette di eseguire comandi DOS:
    http://sample.codeplex.com/SourceControl/changeset/view/61129#1225027


    Matteo Migliore

    Blog http://blogs.ugidotnet.org/matteomigliore
    Twitter http://twitter.com/matteomigliore
    CodePlex http://hyperionsdk.codeplex.com
    • Proposto come risposta Irina Turcu mercoledì 10 agosto 2011 15:27
    • Contrassegnato come risposta Irina Turcu martedì 16 agosto 2011 08:08
    mercoledì 3 agosto 2011 11:18

Tutte le risposte

  • Puoi fare così:
    Public Function SearchFile(ByVal directory As DirectoryInfo, ByVal fileName As String, ByVal logger As ILogger) As FileInfo
    	Dim file = directory.GetFiles(fileName).SingleOrDefault()
    
    	If file IsNot Nothing Then
    		Return file
    	End If
    
    	Dim directories = directory.GetDirectories()
    
    	If directories.Count() = 0 Then
    		Return Nothing
    	End If
    
    	For Each child In directories
    		logger.Debug(child.FullName)
    
    		Dim fileFound = SearchFile(child, fileName, logger)
    
    		If fileFound IsNot Nothing Then
    			Return fileFound
    		End If
    	Next child
    
    	Return Nothing
    End Function
    
    Public Interface ILogger
    	Sub Debug(ByVal message As String)
    End Interface
    
    Public Class ConsoleLogger
    	Implements ILogger
    	Public Sub Debug(ByVal message As String) Implements ILogger.Debug
    		Console.WriteLine(message)
    	End Sub
    End Class
    


    Da usare così:
    Dim root = New DirectoryInfo("c:\temp\")
    
    Dim path = SearchFile(root, "test.txt", New ConsoleLogger())
    

    Puoi scriver un ILogger custom che scriva nella Label.
    Matteo Migliore

    Blog http://blogs.ugidotnet.org/matteomigliore
    Twitter http://twitter.com/matteomigliore
    CodePlex http://hyperionsdk.codeplex.com
    lunedì 1 agosto 2011 22:26
  • Il metodo GetFiles che utilizzi tu esegue già una ricerca ricorsiva dei file, il problema è che potresti andare a leggere delle cartelle per cui non hai i privilegi e, allora, beccheresti un errore di accesso che vanificherebbe l'intera ricerca (è, probabilmente, quello che accade se fai la ricerca su tutto C:). Devi implementare una ricerca ricorsiva come ti ha suggerito Matteo ma mi permetto di inserirci una gestione delle eventuali eccezioni di accesso a cartelle (altrimenti ti ritrovi da capo):

       Public Function GetFilesRecursive(rootPath As String, wildcard As String,
    ByVal logger As ILogger) As IEnumerable(Of String)
           If logger Is Nothing Then Throw New ArgumentNullException()
           Dim list = New List(Of String)
           Try
               list.AddRange(System.IO.Directory.GetFiles(rootPath, wildcard))
               For Each dirPath In System.IO.Directory.GetDirectories(rootPath)
                   logger.Debug(dirPath)
                   list.AddRange(GetFilesRecursive(dirPath, wildcard, logger))
               Next
           Catch ex As Exception
            End Try
           Return list
       End Function

    Volendo potresti eseguire un controllo sui privilegi di accesso alla directory prima di richiederne i file, ma il codice scritto è il minimo indispensabile.

    Come dice Matteo, crei una classe che implementa ILogger e scrivi ovunque tu voglia.
    Il problema è che se metti questo codice nel thread principale della form (ad esempio nel click di un bottone) non vedrai mai nulla perchè la funzione occupa il thread principale che si occupa anche del refresh dell'interfaccia.
    Per questo motivo (un'operazione lunga potrebbe freezare l'interfaccia) ti consiglio di mettere la funzione in un thread separato.
    Potresti utilizzare la classe Task (per maggiori info guarda su MSDN o http://codetailor.blogspot.com/2010/10/i-tasks-del-net-framework-40.html). Nel seguente esempio lancio la ricerca dei file al load della form (ma non mi curo dei risultati che magari a te servono):

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles
    MyBase.Load
       Dim task = New Threading.Tasks.Task(Sub() GetFilesThreadCode())
       task.Start()
    End Sub
    
    Private Sub GetFilesThreadCode()
       Dim logger = New TextBoxLogger(Me.TextBox1)
       Dim files = GetFilesRecursive("c:\", "*.txt", logger)
    End Sub

    dove TextBoxLogger è la suddetta classe che implementa ILogger di Matteo:

    Public Class TextBoxLogger
       Implements ILogger
        Private _Textbox As TextBox
       Public Sub New(textBox As TextBox)
           If textBox Is Nothing Then Throw New ArgumentNullException
           _Textbox = textBox
       End Sub
        Public Sub Debug(message As String) Implements ILogger.Debug
           _Textbox.Text = message
       End Sub
    End Class

    A questo punto non blocchi l'interfaccia ma vedrai che la funzione di recupero dei file va in eccezione, questo capita perchè stai tentando di modificare la UI da un thread che non è quello proprietario della stessa e, questo, poichè le applicazioni .NEt sono STA (Single Thread Apartment) non si pèuò fare. Per risolvere il problema devi eseguire la visualizzazione impersonando il thread principale e per fare questo puoi usare la tecnica dell'Invoke (http://www.domusdotnet.org/pillole/20110701-aggiornare-controlli-da-thread-secondari-con-invoke.aspx):

    Public Class TextBoxLogger
       Implements ILogger
        Private _Textbox As TextBox
       Public Sub New(textBox As TextBox)
           If textBox Is Nothing Then Throw New ArgumentNullException
           _Textbox = textBox
       End Sub
        Public Sub Debug(message As String) Implements ILogger.Debug
           UpdateTextbox(message)
       End Sub
        Private Delegate Sub UpdateTextBoxDelegate(message As String)
        Private Sub UpdateTextbox(message As String)
           If Me._Textbox.InvokeRequired Then
               Me._Textbox.BeginInvoke(New UpdateTextBoxDelegate(AddressOf UpdateTextbox),
    {message})
           Else
               _Textbox.Text = message
           End If
       End Sub
    End Class

    Spero di essere stato chiaro (anche se non esaustivo).

    • Proposto come risposta Irina Turcu mercoledì 10 agosto 2011 15:28
    • Contrassegnato come risposta Irina Turcu martedì 16 agosto 2011 08:08
    martedì 2 agosto 2011 06:56
    Moderatore
  • In genere non fornisco il codice completo di gestione errori per non allungarlo troppo.

    Così come hai scritto il logger vedi solo l'ultimo path, bisogna concaternare il message nella proprietà Text della Label, non riassegnarlo ogni volta.
    Matteo Migliore

    Blog http://blogs.ugidotnet.org/matteomigliore
    Twitter http://twitter.com/matteomigliore
    CodePlex http://hyperionsdk.codeplex.com
    martedì 2 agosto 2011 07:28
  • E' stata una scelta volontaria quella di visualizzare solo il path della directory che sta esaminando, altrimenti avrei creato un log che, anzichè lavorare su un TextBox, deve lavorare su una ListBox, tipo il seguente:

    Public Class ListBoxLogger
       Implements ILogger
        Private _Listbox As ListBox
       Public Sub New(listBox As ListBox)
           If listBox Is Nothing Then Throw New ArgumentNullException
           _Listbox = listBox
       End Sub
        Public Sub Debug(message As String) Implements ILogger.Debug
           UpdateListbox(message)
       End Sub
        Private Delegate Sub UpdateListboxDelegate(message As String)
        Private Sub UpdateListbox(message As String)
           If Me._Listbox.InvokeRequired Then
               Me._Listbox.BeginInvoke(New UpdateListboxDelegate(AddressOf UpdateListbox),
    {message})
           Else
               _Listbox.Items.Insert(0, message)
           End If
       End Sub
    End Class

    Per quanto riguarda la gestione degli errori, neanche io la metto di solito, ma stavolta serviva. La funzione usata in origine già fa la ricerca recursiva ma ha il problema di andare in errore quando si va a leggere una cartella di cui non si hanno gli opportuni diritti.

    Il mio intervento non aveva nulla di critico nei tuoi confronti (scusami se ti ho dato questa impressione) voleva solo dettagliare meglio la soluzione proposta.

    • Proposto come risposta Irina Turcu mercoledì 10 agosto 2011 15:28
    • Contrassegnato come risposta Irina Turcu martedì 16 agosto 2011 08:08
    martedì 2 agosto 2011 08:12
    Moderatore
  • Non ci ho messo i soliti smile :), ma non c'è nessun problema, ho spiegato perchè ho postato il codice così :).

    Sì iterando sulle folder da c:\ si ottiene una UnauthorizedAccessException sulle folder in "Documents".

    Magari pubblico l'esempio completo su http://sample.codeplex.com.

    Matteo Migliore

    Blog http://blogs.ugidotnet.org/matteomigliore
    Twitter http://twitter.com/matteomigliore
    CodePlex http://hyperionsdk.codeplex.com
    martedì 2 agosto 2011 11:16
  • Tutto ok, anche senza gli smiles :-)

    martedì 2 agosto 2011 12:09
    Moderatore
  • Grazie a tutti

     

    ma sinceramente mi sono xso, pensavo ke fosse piu' semplice tutto il codice

     

    cerchero' ai approfondire quello ke mi avete postato

     

    ... se invece volessi inserire in un bottone un label che mi visualizzasse tutti i file e caretella al comando ( del dos ) DIR /s

    e' sempre cosi' complesso?

     

    Graziew di nuovo

    martedì 2 agosto 2011 15:23
  • Il concetto è che enumerare i file di un disco è un lavoro lungo, il thread che gestisce l'interfaccia è uno solamente e se lo occupi a leggere le cartelle non può occuparsi di aggiornare l'interfaccia.
    Se il thread dell'interfaccia è occupato, la finestra si blocca con un effetto decisamente poco carino per l'utente :-).
    Fidati, si tratta solo di capire la prima volta come funziona, poi va tutto liscio.
    Un'alternativa (che non ti ho proposto perchè, secondo me è un pelino più complessa da capire) è quella di utilizzare le nuove API messe a disposizione dal Async CTP (dai un'occhiata all'indirizzo http://msdn.microsoft.com/en-us/vstudio/gg316360).

    Per qualsiasi domanda chiedi, qui trovi sicuramente qualcuno in grado di darti una risposta.

    martedì 2 agosto 2011 16:07
    Moderatore
    • Proposto come risposta Irina Turcu mercoledì 10 agosto 2011 15:27
    • Contrassegnato come risposta Irina Turcu martedì 16 agosto 2011 08:08
    martedì 2 agosto 2011 22:14
  • Ho pubblicato qui l'applicazione che cicla sulle directory:
    http://sample.codeplex.com/SourceControl/changeset/view/61129#1224949

    Mentre qui trovi l'applicazione che permette di eseguire comandi DOS:
    http://sample.codeplex.com/SourceControl/changeset/view/61129#1225027


    Matteo Migliore

    Blog http://blogs.ugidotnet.org/matteomigliore
    Twitter http://twitter.com/matteomigliore
    CodePlex http://hyperionsdk.codeplex.com
    • Proposto come risposta Irina Turcu mercoledì 10 agosto 2011 15:27
    • Contrassegnato come risposta Irina Turcu martedì 16 agosto 2011 08:08
    mercoledì 3 agosto 2011 11:18
  • @   Massimo Bonanni  grazie per la disponibilita' e l'aiuto ke voi tutti mi date

     

    @ Matteo Migliore  grazie per tutto l'impegno che metti a dosposizione

     

    ma purtroppo sono un auto didatta e sto imparando passo passo

     

    in quello che mi avete postato c'ho capito meno di prima

     

    Grazie a tutti

     

    al prox quesito

    mercoledì 3 agosto 2011 14:55
  • Prova a guardare l'esempio ShellCommand, è abbastanza semplice, sostanzialmente permette di eseguire qualsiasi comando DOS e vederne l'output in una TextBox, ovviamente puoi impostare il command da eseguire senza farlo inserire all'utente, che potrebbe fare danni.
    Matteo Migliore

    Blog http://blogs.ugidotnet.org/matteomigliore
    Twitter http://twitter.com/matteomigliore
    CodePlex http://hyperionsdk.codeplex.com
    mercoledì 3 agosto 2011 15:04
  • Se non hai capito, dicci cosa esattamente non ti è chiaro e vediamo di darti una mano.

    Non hai capito la funzione che recupera i nomi dei file, il meccanismo di visualizzazione con l'interfaccia ILogger di Matteo oppure il discroso multithread?

    mercoledì 3 agosto 2011 15:52
    Moderatore
  • cio' che non mi e' chiaro non sono i vs post ma tutta la programmazione che avete postato, non sono ancora a quel livello

     

    cio che mi ha fornito Matteo non so da dove iniziare

     

    ripeto sono un auto didatta e sto imparando da solo e sono ad un livello molto lontano dal vs

    mercoledì 3 agosto 2011 17:24
  • Allora intanto usa la classe BackgroundWorker e Directory.GetFiles senza visualizzare la directory corrente di ricerca ma solo il risultato, senza bloccare la UI.

    Se ti serve un altro esempio chiedi pure :).
    Matteo Migliore

    Blog http://blogs.ugidotnet.org/matteomigliore
    Twitter http://twitter.com/matteomigliore
    CodePlex http://hyperionsdk.codeplex.com
    mercoledì 3 agosto 2011 17:34
  • Ciao svgl75,

    I concetti che Matteo e Massimo hanno utilizzato nelle loro soluzioni e con lo studio di quali potresti iniziare sono i seguenti:

    Spero che queste informazioni ti siano utili per iniziare. Non esitare a postare sul forum nel caso ti necessitasse ulteriore aiuto.

     

    Saluti,

    Irina


    Questo contenuto è distribuito “as is” e non implica alcuna responsabilità da parte di Microsoft. L'azienda offre questo servizio gratuitamente, allo scopo di aiutare gli utenti e farli aumentare la conoscenza sui prodotti e le tecnologie Microsoft.

    LinkedIn

    mercoledì 10 agosto 2011 15:26
  • Precisazione: ILogger nel mio esempio è un'interfaccia "inventata" :), non è quella di MSBuild.
    Matteo Migliore

    Blog http://blogs.ugidotnet.org/matteomigliore
    Twitter http://twitter.com/matteomigliore
    CodePlex http://hyperionsdk.codeplex.com
    mercoledì 10 agosto 2011 15:30
  • Grazie, Matteo, per il chiarimento :)

     

    Irina


    Questo contenuto è distribuito “as is” e non implica alcuna responsabilità da parte di Microsoft. L'azienda offre questo servizio gratuitamente, allo scopo di aiutare gli utenti e farli aumentare la conoscenza sui prodotti e le tecnologie Microsoft.

    LinkedIn

    giovedì 11 agosto 2011 08:57
  • scusate il ritardo

     

    GRAZIE a tutti x l'aiuto

     

    sto cercando man mano di apprendere quante piu' cose possibile

     

    vi chiedero' aiuto sicuramente

     

    Grazie di nuovo

    lunedì 15 agosto 2011 14:35