Cercare e Selezionare una Cartella (Folder o Directory). - pagina vista: volte

Requisiti: conoscenza VBA e struttura delle Directory.

Utilizzo della proprietà: FileDialog  - Questo articolo descrive come mostrare una finestra di dialogo per richiedere all'utente di scegliere una cartella. (testato con Excel 2003 e Excel 2007) . Risolto Il problema presente con qualsiasi altra funzione o proprietà che non "leggendo" in modo così semplice e lineare tutte le cartelle e sottocartelle contenute in un hard-disk, hanno bisogno di essere implementate in routine o funzioni ricorsive.

L'antefatto.

Mi sono ritrovato ad avere la necessità di stampare un elenco di files presenti in una determinata cartella (nomi di file immagini) e volendo realizzare la procedura con Excel importando l'elenco in una colonna per poi stamparlo, (esistono programmi free per ottenere dette stampe) e non volendo seguire le procedure già spiegate in articoli sui miei due siti per comporre un elenco di files  (vedi ad esempio : vba8.php o anche ifvba128.htm ) , ho trovato alcune difficoltà:

  1. I metodi che prevedono l'utilizzo dell'"Oggetto" FileSearch (peraltro il FileSearch non lavora in Excel 2007) richiedono la definizione del "percorso" che mira alla Directory (o Folder) da assegnare ad una variabile, scrivendo il "percorso completo di path " in una InputBox, direttamente nel codice, o tramite testo in celle del foglio.

  2. Anche usando il metodo CreateObject(Scripting.FileSystemObject) si deve comunque prevedere  il "percorso completo" che mira alla cartella contenente i files, e detto "percorso" deve essere assegnato come sopra (manualmente ad una variabile o una costante definita nel codice).

  3. i due punti sopra rendono la scelta dei "percorsi" sicuramente preordinata e niente affatto automatizzabile.

In Excel quando si voglia reperire e memorizzare il nome (completo di percorso) di un file, possiamo usare il metodo GetOpenFileName, ma quando desideriamo "sfogliare" l'albero delle Directory per "prendere" il nome (e il "percorso") di una cartella (Directory o Folder) ci troviamo, pare, senza "armi", cioè diventa difficile individuare il metodo da seguire.

Se infatti cerchiamo in Internet qualche soluzione, possiamo ad esempio trovare in questo Link http://www.cpearson.com/excel/BrowseFolder.aspx
due validi suggerimenti per realizzare una finestra "Browser Folder": uno è un metodo basato sull'utilizzo delle Funzioni API di Windows e l'altro sull'utilizzo della
Shell Controls Library (vedi articolo al Link segnalato) e comunque l'autore (un autore di tutto rispetto) dice addirittura che in Excel NON esiste la possibilità di avere un "Navigatore per le Directory" : "..While Excel has a built in File Open method (GetOpenFileName), it does not provide a method to browse for a folder.."(ndr. : alla data inizio 2011 l'articolo citato risulta modificato con l'inserimento di un terzo sistema, rappresentato appunto dal FileDialog....)

Invece Excel consente in maniera nativa di "sfogliare" le cartelle e di memorizzare il percorso della cartella scelta, con l'Oggetto FileDialog.

Perchè automatizzare la selezione (e la scelta) di una cartella?

Usare una finestra di dialogo rende la selezione una scelta indipendente e veloce consentendoci di rendere veramente variabile il "percorso",  a piacimento.

 

L'"Oggetto" FileDialog.  (Excel, come Application, possiede la "proprietà" FileDialog che restituisce appunto l'oggetto FileDialog, cioè una finestra di "scelta")

L'"Oggetto" FileDialog ci consente comunque non solo di selezionare una directory o cartella che dir si voglia, ma consente pure di selezionare uno o più file contenuti in una cartella (ed importarne, volendo, l'elenco in un foglio di lavoro), oltre ad altre due azioni interessanti: aprire file o salvare file, vediamo come:

La sintassi dell'istruzione (vedi guida in linea nel vostro computer) richiede anche la definizione di un argomento (di tipo MsoFileDialogType) che qualifichi il tipo di finestra che vogliamo far apparire, argomento rappresentato da una delle seguenti costanti:

  1. msoFileDialogFilePicker  Consente di selezionare un file

  2. msoFileDialogFolderPicker  Consente di selezionare una cartella.

  3. msoFileDialogOpen  Consente di aprire un file.

  4. msoFileDialogSaveAs  Consente di salvare un file.

In questo articolo ci occuperemo solo di selezionare una cartella (msoFileDialogFolderPicker) e di selezionare uno o più  file (msoFileDialogFilePicker) -

l'istruzione base necessaria per far apparire la finestra per la selezione di una directory sarà:

  • With Application.FileDialog(msoFileDialogFolderPicker)
    .Show   
    '
    si applica il metodo Show per mostrare la finestra di dialogo per la scelta di una directory, alias Folder, alias Cartella
    End With

per intenderci, ad esempio, apparirà questa:

Chiaramente possiamo selezionare cartelle, sottocartelle, sottosotto cartelle, etc. etc. fino a che non raggiungeremo e selezioneremo la cartella desiderata. In questo tipo di applicazione scelta (msoFileDialogFolderPicker), poichè abbiamo scelto di "Navigare tra Cartelle", nella parte centrale della finestra di dialogo NON vedremo eventuali file presenti; è normale.

Nella finestra "Sfoglia" i nomi delle cartelle sono rappresentate da tanti "Item" quante sono le cartelle presenti nella finestra stessa, cioè vengono viste come "parti" (Items) di un "insieme" (Collection (le Folder)), e selezionare una cartella e premere il pulsante "OK" restituisce il "percorso" completo che porta alla cartella stessa; se assegneremo detto "percorso" ad una variabile avremo ottenuto con un semplice click quel "percorso" che ci necessita per raggiungere i nostri files.

Avremo reso cioè la definizione di un "percorso" una operazione veloce, adattabile alle esigenze del momento, libera da assegnazioni preordinate nel codice, e slegata dal path e dalle directory presenti nel computer sul quale la routine è nata.

 

Applicazioni pratiche.

La guida in linea ci insegna: per poter sfruttare le caratteristiche dell'oggetto FileDialog, avremo bisogno di creare un ciclo For Each Next che, scorrendo l'insieme degli Item (le Cartelle) presenti nella finestra di dialogo, memorizzi la cartella selezionata al click sul pulsante "OK", e la "Finestra di dialogo" di selezione delle cartelle viene visualizzata utilizzando il metodo Show dell'oggetto FileDialog ed il percorso selezionato viene acquisito nell'insieme FileDialogSelectedItems.

Sarà quindi l'Item (la cartella) selezionato nell'insieme SelectedItems che restituirà il "percorso" completo che mira alla nostra cartella. Assegneremo ad una variabile detto "percorso" che useremo per le nostre necessità.

Prima di passare ad esaminare le istruzioni, è meglio chiarire alcuni punti ricordando che:

  1. La necessità è quella di ottenere un elenco di nomi di files presenti in una cartella, da stampare successivamente.

  2. Vogliamo la possibilità di poter scegliere con semplicità e velocità, sfogliando le cartelle, di quale cartella ottenere l'elenco dei files ivi contenuti.

  3. NON desideriamo che nell'elenco compaia il "percorso" completo di path e nomi di cartelle e/o sotto cartelle, ma SOLTANTO il nome del file.

Per il motivo di cui al punto 3. usiamo la costante msoFileDialogFolderPicker , (che restituisce il percorso che mira alla cartella, a cui facciamo seguire istruzioni appropriate per "caricare" i nomi dei files) e NON già la costante msoFileDialogFilePicker  che ci consentirebbe di ottenere la lista dei files selezionati nella finestra di dialogo, MA comprensivi del percorso completo.

Ecco quindi tre esempi con tre routine diverse:

  1. la macro SelezionaCartella_CaricaNomiFiles() - oltre al FileDialog(msoFileDialogFolderPicker) usiamo la Funzione CreateObject("Scripting.FileSystemObject") per "caricare" l'elenco dei soli nomi dei files, senza il "percorso".

  2. la macro SelezionaCartella_e_Seleziona_NomiFiles() - useremo il FileDialog(msoFileDialogFilePicker) e un ciclo che per ogni nome di files selezionato nella finestra di dialogo, scriva il nome del file completo di "percorso" in celle del foglio di lavoro, creando l'elenco, senza l'utilizzo di funzioni aggiunte (il CreateObjects)

  3. la macro SelezionaCartella_e_Seleziona_Solo_NomiFiles() - simile al punto B., ma inseriamo la funzione CreateObject("Scripting.FileSystemObject") per poter utilizzare il metodo GetParentFolderName (che restituisce il percorso di un file MA solo fino alla cartella che lo contiene) eliminiamo il "percorso" e teniamo SOLO il nome del nome  di cui creeremo l'elenco.

precisazione: le macro di cui ai punti A. e C. sono simili (restituiscono entrambe il SOLO nome dei files) ma differiscono in modo sostanziale:

  • la macro SelezionaCartella_CaricaNomiFiles() - restituisce TUTTI i nomi dei files presenti nella cartella selezionata.

  • la macro SelezionaCartella_e_Seleziona_Solo_NomiFiles() - restituisce SOLTANTO i nomi dei files che avremo selezionato nella finestra che ci ha condotto alla cartella selezionata.

Vediamo le macro e relative spiegazioni:

Sub SelezionaCartella_CaricaNomiFiles()

Dim fd As FileDialog    
'Dichiarazione della variabile "fd" come una variabile FileDialog object.
Set fd = Application.FileDialog(msoFileDialogFolderPicker)   
 'creiamo l'oggetto FileDialog come finestra di dialogo per le cartelle e lo 'assegniamo alla variabile "fd"

'Sotto: dichiarariamo la variabile "CartellaSelezionata" che conterrà il percorso della cartella selezionata. Sebbene il percorso sia una 'Stringa la variabile deve essere Variant perché il Ciclo For Each... Next lavora solo con variabili Variant o Objects
Dim CartellaSelezionata As Variant

With fd   '
Usiamo  l'istruzione With...End With per eseguire una serie di istruzioni  con l'oggetto FileDialog.

'Usiamo il metodo Show per mostrare la dialog box ed usiamo la condizione If per verificare se l'utente ha premuto il pulsante (di azione, 'di conferma) "OK"

If .Show = -1 Then 
'se è stato premuto il pulsante di conferma che restituisce  -1 (il pulsante di annullamento restituirebbe 0) allora:

'iniziamo un ciclo For Each Next necessario per scorrere l'insieme delle cartelle (la Colletion del FileDialogSelectedItems) nella finestra '"Sfoglia".
For Each CartellaSelezionata In .SelectedItems

miaCartella = CartellaSelezionata 
'assegniamo alla variabile "miaCartella" il percorso della cartella che avremo selezionato

Next
Else        
 'se invece avremo premuto annullamento
Exit Sub          '
usciamo dalla routine.
End If     
 'fine della condizione da verificare
End With  
 'fine istruzione With

'Se siamo a questo punto abbiamo automatizzato la memorizzazione del "percorso" completo che mira alla cartella al 'cui interno sono i files di cui vogliamo l'elenco, ed ora usiamo la funzione CreateObject per scorrere e leggere tutti i 'nomi dei files nel percorso "miaCartella", e con un ciclo For Each Next leggiamo il nome di ogni file e tramite un ciclo 'While..Wend interno, cerchiamo la prima cella libera dove scrivere quel nome di file. Il tutto avviene in automatico.

Dim fs, F, Nomefile, Cartella
Set fs = CreateObject("Scripting.FileSystemObject")
Set F = fs.GetFolder(miaCartella)
Set Cartella = F.Files

For Each Nomefile In Cartella 
'si inizia il ciclo che per ogni file (Nomefile) presente in Cartella
DoEvents
'sotto: iniziamo la ricerca di una cella libera, a partire dalla riga 2 (iRow = 2) e dalla colonna 1 (la A icol = 1) usando il ciclo While..Wend
Dim iRow, icol As Integer
iRow = 2   '
inizio la ricerca dalla riga 2 del foglio come esempio, ognuno deciderà da quale riga iniziare l'elenco dei nomi dei files
icol = 1     '
e dalla colonna 1 la colonna A
While Cells(iRow, icol).Value <> ""
iRow = iRow + 1
Wend
Cells(iRow, icol) = Nomefile.Name
'nella cella libera andrà il nome del file letto (per ogni "NomeFile"...)

Next
'continua il ciclo fino alla fine dei files presenti nella cartella scelta.

Set fs = Nothing 
 'eliminiamo le variabili dalla memoria
Set Cartella = Nothing
Set F = Nothing
Set fd  = Nothing

End Sub

 

la seconda macro che consente invece di selezionare i file di cui vogliamo importare il nome (però completo di "percorso" (il Path)):

Sub SelezionaCartella_e_Seleziona_NomiFiles()

 
Dim fd As FileDialog   'Dichiarazione della variabile "fd" come  FileDialog object.

Set fd = Application.FileDialog(msoFileDialogFilePicker)   'creiamo l'oggetto FileDialog come finestra di dialogo per le cartelle e lo 'assegniamo alla variabile "fd"
'Sotto: dichiariamo la variabile "FileSelezionato" che conterrà il "percorso" completo dei files selezionati. Sebbene il percorso sia una 'Stringa la variabile deve essere Variant perché il Ciclo For Each... Next lavora solo con variabili Variant o Objects
Dim FileSelezionato As Variant

With fd         '
Usiamo  l'istruzione With...End With per eseguire una serie di istruzioni  con l'oggetto FileDialog.

'Usiamo il metodo Show per mostrare la dialog box ed usiamo la condizione If per verificare se l'utente ha premuto il pulsante (di azione, 'di conferma) "OK"
If .Show = -1 Then    
'se la condizione si è verificata, allora....

'iniziamo un ciclo For Each Next necessario per scorrere l'insieme dei files che avremo selezionato (e SOLO QUELLI) (la Colletion del 'FileDialogSelectedItems) nella finestra '"Sfoglia" - sarà possibile selezionare anche files non contigui tenendo premuto il tasto 'CTRL (Control) mentre si selezionano i files.
For Each FileSelezionato In .SelectedItems

'FileSelezionato è ora una stringa che contiene il path (il percorso) di ogni Item (.In SelectedItems)  selezionato.
'e per ogni FileSelezionato iniziamo un ciclo interno While..Wend che cerchi la prima cella libera e ci scriva nome e percorso.
Dim iRow, icol As Integer
iRow = 2   '
inizio la ricerca dalla riga 2 del foglio come esempio
icol = 1     '
e dalla colonna 1 la colonna A
While Cells(iRow, icol).Value <> ""
iRow = iRow + 1
Wend
Cells(iRow, icol) = FileSelezionato


Next FileSelezionato

Else  
 'se invece l'utente avrà premuto il pulsante annulla, si esce dall'istruzione
End If
End With

'
 eliminiamo la variabile oggetto dalla memoria
Set fd = Nothing

End Sub


vediamo due immagini di come lavora la macro SelezionaCartella_e_Seleziona_NomiFiles() :  a sinistra la dialog box (FileDialog) "Sfoglia" dove si notano i files selezionati, tra l'altro in modo non conseguente, e a destra l'elenco con i nomi dei file selezionati, COMPRENSIVI di percorso (Unità hard-disk, cartella, sottocartella, nome ed estensione del file)


 


La terza macro la usiamo quando desideriamo comporre un elenco dei SOLI nomi (con estensione) dei files ma NON desideriamo far comparire il suo percorso completo: (commento solo le istruzioni diverse)

Sub SelezionaCartella_e_Seleziona_Solo_NomiFiles()

Dim FsO
Dim LPT
   'lunghezza totale caratteri stringa del percorso completo di nome del file
Dim LPC  
' lunghezza percorso all'ultima cartella senza il nome del file
Dim SoloNomeFile
      'il solo nome di ogni file selezionato

Dim Differenza As Integer
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
Set FsO = CreateObject("Scripting.FileSystemObject")

Dim Selezionato As Variant
With fd

If .Show = -1 Then
For Each Selezionato In .SelectedItems

LPC = Len(FsO.GetParentFolderName(Selezionato)) '
usiamo il metodo GetParentFolderName del FsO che restituisce il percorso fino
'all'ultima cartella contenente i files cercati


LPT = Len(Selezionato)  
Differenza = (LPT - LPC) - 1   
'facciamo la differenza sottraendo il percorso fino all'ultima cartella dal percorso (più lungo) contenente 'anche il nome del file
SoloNomeFile = Right(Selezionato, Differenza)
 'quindi con Right prendiamo nella stringa, iniziando da destra,  solo la quantità di 'caratteri  rappresentata dal numero "Differenza" e lo assegniamo alla variabile SoloNomeFile
Dim iRow, icol As Integer 
 'ora cerchiamo la prima cella libera nella colonna 1 dove registra il nome del file
iRow = 2
icol = 1
While Cells(iRow, icol).Value <> ""
iRow = iRow + 1
Wend
Cells(iRow, icol) = SoloNomeFile

Next Selezionato
Else
End If
End With

Set fd = Nothing
Set FsO = Nothing
End Sub

e la routine sopra restituirà solo i nomi dei file (vedi sotto, senza il percorso completo) che avremo selezionato nella cartella scelta.

 

buon lavoro.

prelevato sul sito www.ennius.altervista.org