os.walk
di Python è uno strumento potente per esplorare ricorsivamente una directory e i suoi contenuti. Utilizzando questa funzione, è possibile ottenere facilmente tutte le sottodirectory e i file di una directory specificata. In questo articolo, esploreremo dall’uso di base di os.walk
a esempi pratici, in modo da rendere più efficienti i compiti che coinvolgono operazioni sulle directory.
Che cos’è os.walk
os.walk
è una funzione inclusa nel modulo standard os
di Python, che esplora ricorsivamente una directory specificata e genera un elenco dei file e delle sottodirectory all’interno di quella directory. Usando questa funzione, è possibile esplorare facilmente strutture di directory complesse, rendendo molto semplice ottenere elenchi di file e cartelle.
Come funziona os.walk
os.walk
funziona come un generatore e restituisce un tuple contenente i seguenti 3 elementi.
- Percorso della directory (
dirpath
)
Il percorso della directory attualmente esplorata. - Elenco delle sottodirectory (
dirnames
)
Elenco dei nomi delle sottodirectory nella directory corrente. - Elenco dei file (
filenames
)
Elenco dei nomi dei file nella directory corrente.
Caratteristiche
- Esplorazione ricorsiva: Esplora automaticamente le sottodirectory della directory specificata.
- Ordine: È possibile configurare il trattamento della gerarchia delle directory in modalità top-down o bottom-up (
topdown=True/False
). - Efficienza: Genera informazioni al volo, quindi è molto efficiente in termini di memoria.
Usi
- Ricerca di nomi di file
- Creazione di un elenco di file con un’estensione specifica
- Calcolo delle dimensioni delle sottodirectory
- Automatizzazione di attività di backup o spostamento
Uso di base
Utilizzando os.walk
, è facile ottenere file e cartelle all’interno di una directory specificata. Ecco un esempio di codice di base.
Esempio di codice
import os
# Specificare la directory di destinazione
target_directory = "/path/to/your/directory"
# Esplorare la directory utilizzando os.walk
for dirpath, dirnames, filenames in os.walk(target_directory):
print(f"Percorso attuale: {dirpath}")
print(f"Sottodirectory: {dirnames}")
print(f"File: {filenames}")
print("-" * 40)
Esempio di output
Immagina che la struttura delle directory sia la seguente:
/path/to/your/directory
├── file1.txt
├── file2.txt
├── subdir1
│ └── file3.txt
└── subdir2
└── file4.txt
In questo caso, l’esecuzione di os.walk
restituirà il seguente output:
Percorso attuale: /path/to/your/directory
Sottodirectory: ['subdir1', 'subdir2']
File: ['file1.txt', 'file2.txt']
----------------------------------------
Percorso attuale: /path/to/your/directory/subdir1
Sottodirectory: []
File: ['file3.txt']
----------------------------------------
Percorso attuale: /path/to/your/directory/subdir2
Sottodirectory: []
File: ['file4.txt']
----------------------------------------
Spiegazione
- dirpath: Percorso della directory attualmente esplorata.
- dirnames: Elenco delle sottodirectory nella directory attuale.
- filenames: Elenco dei file nella directory attuale.
Punti di attenzione
os.walk
genera un errore se la directory specificata non esiste, quindi è consigliabile verificare prima se la directory esiste.
Gestione dei file e delle directory separati
Usando os.walk
, puoi facilmente separare file e cartelle all’interno di una directory. Se desideri applicare operazioni diverse a ciascuno di essi, puoi semplicemente aggiungere delle istruzioni condizionali.
Esempio di codice
Ecco un esempio che separa i file dalle sottodirectory e applica operazioni diverse su ciascuno:
import os
# Specificare la directory di destinazione
target_directory = "/path/to/your/directory"
# Esplorare la directory e separare i file dalle sottodirectory
for dirpath, dirnames, filenames in os.walk(target_directory):
# Operazioni sulle sottodirectory
for dirname in dirnames:
subdir_path = os.path.join(dirpath, dirname)
print(f"Directory: {subdir_path}")
# Operazioni sui file
for filename in filenames:
file_path = os.path.join(dirpath, filename)
print(f"File: {file_path}")
Esempio di output
Supponiamo che la struttura della directory sia la seguente:
/path/to/your/directory
├── file1.txt
├── file2.txt
├── subdir1
│ └── file3.txt
└── subdir2
└── file4.txt
L’output sarà il seguente:
Directory: /path/to/your/directory/subdir1
Directory: /path/to/your/directory/subdir2
File: /path/to/your/directory/file1.txt
File: /path/to/your/directory/file2.txt
File: /path/to/your/directory/subdir1/file3.txt
File: /path/to/your/directory/subdir2/file4.txt
Spiegazione del codice
os.path.join
: Uniscedirpath
condirname
ofilename
per creare il percorso assoluto.- Elaborazione delle directory (
for dirname in dirnames
): È possibile applicare operazioni specifiche sulle directory, come ottenere la data di creazione. - Elaborazione dei file (
for filename in filenames
): È possibile applicare operazioni specifiche sui file, come ottenere la dimensione del file.
Esempi avanzati
- Creare e gestire un elenco di sottodirectory.
- Estrazione e elaborazione di file che seguono una determinata convenzione di nomi.
- Filtrare i file in base a dimensioni o data di creazione.
Ricerca di file con una specifica estensione
Utilizzando os.walk
, è facile cercare file con una determinata estensione. Ad esempio, è possibile estrarre file con estensioni come .txt
o .jpg
in modo molto efficiente.
Esempio di codice
Ecco un esempio di codice che cerca file con estensione .txt
e stampa il loro percorso:
import os
# Specificare la directory di destinazione
target_directory = "/path/to/your/directory"
# Specificare l'estensione da cercare
target_extension = ".txt"
# Cercare i file con l'estensione specificata
for dirpath, dirnames, filenames in os.walk(target_directory):
for filename in filenames:
if filename.endswith(target_extension):
file_path = os.path.join(dirpath, filename)
print(f"Trovato: {file_path}")
Esempio di output
Se la struttura delle directory è la seguente:
/path/to/your/directory
├── file1.txt
├── file2.doc
├── subdir1
│ └── notes.txt
└── subdir2
└── image.png
L’output sarà:
Trovato: /path/to/your/directory/file1.txt
Trovato: /path/to/your/directory/subdir1/notes.txt
Spiegazione del codice
filename.endswith(target_extension)
: Restituisce True se il nome del file termina con l’estensione specificata. Questo viene usato per filtrare i file in base al loro formato.os.path.join
: Viene usato per generare il percorso completo del file.
Ricerca di file con più estensioni
Se si desidera cercare file con più estensioni, è possibile modificare la condizione in questo modo.
# Specificare le estensioni da cercare in una lista
target_extensions = [".txt", ".doc"]
for dirpath, dirnames, filenames in os.walk(target_directory):
for filename in filenames:
if filename.endswith(tuple(target_extensions)):
file_path = os.path.join(dirpath, filename)
print(f"Trovato: {file_path}")
Esempi avanzati
- Recuperare un elenco di file di codice sorgente (ad esempio, file
.py
) in un progetto. - Cercare e processare file in formati di immagine specifici (ad esempio,
.jpg
o.png
). - Creare statistiche sui file in base alle loro estensioni.
Esplorazione con limitazione della profondità della directory
os.walk
esplora per impostazione predefinita tutte le sottodirectory in modo ricorsivo. Tuttavia, a volte è necessario esplorare solo fino a una determinata profondità. In tal caso, è possibile monitorare la profondità corrente e limitare l’esplorazione a un certo livello.
Esempio di codice
Ecco un esempio che limita l’esplorazione alla profondità 2:
import os
# Specificare la directory di destinazione
target_directory = "/path/to/your/directory"
# Specificare la profondità massima di esplorazione
max_depth = 2
# Esplorazione con limitazione della profondità
for dirpath, dirnames, filenames in os.walk(target_directory):
# Calcolare la profondità corrente
current_depth = dirpath.count(os.sep) - target_directory.count(os.sep) + 1
if current_depth > max_depth:
# Se la profondità è maggiore del limite, saltare le sottodirectory
del dirnames[:] # Rimuovere tutte le sottodirectory
continue
print(f"Profondità {current_depth}: {dirpath}")
print(f"Sottodirectory: {dirnames}")
print(f"File: {filenames}")
print("-" * 40)
Esempio di output
Supponiamo che la struttura delle directory sia la seguente:
/path/to/your/directory
├── file1.txt
├── subdir1
│ ├── file2.txt
│ └── subsubdir1
│ └── file3.txt
└── subdir2
└── file4.txt
Con una limitazione alla profondità 2, l’output sarà:
Profondità 1: /path/to/your/directory
Sottodirectory: ['subdir1', 'subdir2']
File: ['file1.txt']
----------------------------------------
Profondità 2: /path/to/your/directory/subdir1
Sottodirectory: ['subsubdir1']
File: ['file2.txt']
----------------------------------------
Profondità 2: /path/to/your/directory/subdir2
Sottodirectory: []
File: ['file4.txt']
----------------------------------------
Spiegazione del codice
os.sep
: Restituisce il separatore di percorso dipendente dal sistema operativo (ad esempio\\
su Windows,/
su Unix).dirpath.count(os.sep)
: Conta il numero di separatori di percorso indirpath
per calcolare la profondità corrente.del dirnames[:]
: Svuota la lista delle sottodirectory per evitare che vengano esplorate ulteriormente.
Esempi avanzati
- Esplorare solo le directory di livello superiore in un progetto di grandi dimensioni.
- Visualizzare una parte della struttura ad albero con limiti di profondità.
- Ridurre il carico di lavoro durante l’esplorazione su disco limitando la profondità di ricerca.
Ignorare i file o le cartelle nascoste
Quando esplori una directory, potrebbe essere utile ignorare i file o le cartelle nascoste (che di solito iniziano con un punto .
). Con os.walk
, puoi filtrare facilmente questi elementi per un’elaborazione più efficiente.
Esempio di codice
Ecco un esempio che ignora i file e le cartelle nascoste durante l’esplorazione:
import os
# Specificare la directory di destinazione
target_directory = "/path/to/your/directory"
# Esplorazione ignorando file e cartelle nascoste
for dirpath, dirnames, filenames in os.walk(target_directory):
# Ignorare le cartelle nascoste
dirnames[:] = [d for d in dirnames if not d.startswith(".")]
# Ignorare i file nascosti
visible_files = [f for f in filenames if not f.startswith(".")]
print(f"Percorso attuale: {dirpath}")
print(f"Sottodirectory: {dirnames}")
print(f"File: {visible_files}")
print("-" * 40)
Esempio di output
Se la struttura delle directory è la seguente:
/path/to/your/directory
├── file1.txt
├── .hidden_file.txt
├── subdir1
│ ├── file2.txt
│ └── .hidden_folder
│ └── file3.txt
└── subdir2
└── file4.txt
Ignorando i file e le cartelle nascoste, l’output sarà:
Percorso attuale: /path/to/your/directory
Sottodirectory: ['subdir1', 'subdir2']
File: ['file1.txt']
----------------------------------------
Percorso attuale: /path/to/your/directory/subdir1
Sottodirectory: []
File: ['file2.txt']
----------------------------------------
Percorso attuale: /path/to/your/directory/subdir2
Sottodirectory: []
File: ['file4.txt']
----------------------------------------
Spiegazione del codice
- Ignorare le cartelle nascoste (
dirnames[:] = ...
): Viene sovrascritta la listadirnames
per escludere le cartelle che iniziano con un punto (.
), impedendo l’esplorazione di tali directory. - Ignorare i file nascosti (
[f for f in filenames ...]
): Usando la comprensione delle liste, si escludono i file che iniziano con un punto (.
) dalla lista dei file.
Punti di attenzione
- Se i file o le cartelle sono impostati come “nascosti” tramite attributi di sistema (soprattutto su Windows), il codice sopra non li rileverà. In tal caso, è necessario usare moduli aggiuntivi (ad esempio
ctypes
).
Esempi avanzati
- Escludere file di configurazione nascosti (come
.gitignore
o.env
) durante l’elaborazione. - Creare un elenco di directory visibili per gli utenti, escludendo le cartelle nascoste.
- Durante la pulizia di grandi set di dati, escludere gli elementi nascosti.
Esempio pratico: Calcolare la dimensione di una directory
Con os.walk
, è possibile sommare le dimensioni di tutti i file all’interno di una directory specifica per calcolare la dimensione totale della directory. Questo è utile per determinare quanto spazio di archiviazione una cartella sta occupando.
Esempio di codice
Ecco un esempio di codice per calcolare la dimensione di una directory:
import os
# Specificare la directory di destinazione
target_directory = "/path/to/your/directory"
def calculate_directory_size(directory):
total_size = 0
# Esplorare la directory
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
file_path = os.path.join(dirpath, filename)
try:
# Aggiungere la dimensione del file
total_size += os.path.getsize(file_path)
except FileNotFoundError:
# Gestire l'eccezione se il file è stato eliminato
pass
return total_size
# Calcolare la dimensione della directory
directory_size = calculate_directory_size(target_directory)
# Stampare il risultato (in byte e MB)
print(f"Dimensione della directory: {directory_size} bytes")
print(f"Dimensione della directory: {directory_size / (1024 ** 2):.2f} MB")
Esempio di output
Se la struttura delle directory è la seguente:
/path/to/your/directory
├── file1.txt (500 bytes)
├── subdir1
│ ├── file2.txt (1500 bytes)
│ └── file3.txt (3000 bytes)
└── subdir2
└── file4.txt (2000 bytes)
Il risultato dell’esecuzione sarà il seguente:
Dimensione della directory: 7000 bytes
Dimensione della directory: 0.01 MB
Spiegazione del codice
os.path.getsize(file_path)
: Ottiene la dimensione di un file in byte.- Gestione delle eccezioni: Gestisce il caso in cui un file venga rimosso o non sia accessibile durante l’elaborazione.
- Conversione delle unità: Converte la dimensione del file da byte a una forma più leggibile (KB, MB, ecc.).
Esempio pratico: Calcolare la dimensione dei file con una specifica estensione
Per calcolare la dimensione totale dei file con una specifica estensione, è possibile modificare il codice come segue:
def calculate_size_by_extension(directory, extension):
total_size = 0
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
if filename.endswith(extension):
file_path = os.path.join(dirpath, filename)
try:
total_size += os.path.getsize(file_path)
except FileNotFoundError:
pass
return total_size
# Esempio: Calcolare la dimensione totale dei file .txt
txt_size = calculate_size_by_extension(target_directory, ".txt")
print(f"Dimensione dei file .txt: {txt_size} bytes")
Praticità
- Monitorare l’uso del disco su server o cloud storage.
- Verificare il consumo di risorse di una cartella di progetto specifica.
- Assistere nelle operazioni di pulizia quando lo spazio su disco è insufficiente.
Esempio pratico: Creazione di una copia di backup di tutti i file
Utilizzando os.walk
, puoi esplorare ricorsivamente una directory e copiare tutti i file in una destinazione di backup. Questo ti permette di creare una copia di sicurezza dell’intera struttura delle directory.
Esempio di codice
Di seguito un esempio di codice che copia i file in una directory di backup:
import os
import shutil
# Specificare la directory di origine e quella di backup
source_directory = "/path/to/your/source_directory"
backup_directory = "/path/to/your/backup_directory"
def backup_files(source, backup):
for dirpath, dirnames, filenames in os.walk(source):
# Calcolare il percorso di backup
relative_path = os.path.relpath(dirpath, source)
backup_path = os.path.join(backup, relative_path)
# Creare la directory di backup se non esiste
os.makedirs(backup_path, exist_ok=True)
for filename in filenames:
source_file = os.path.join(dirpath, filename)
backup_file = os.path.join(backup_path, filename)
try:
# Copiare il file
shutil.copy2(source_file, backup_file)
print(f"Copiato: {source_file} -> {backup_file}")
except Exception as e:
print(f"Impossibile copiare {source_file}: {e}")
# Eseguire il backup
backup_files(source_directory, backup_directory)
Esempio di output
Se la struttura delle directory è la seguente:
/path/to/your/source_directory
├── file1.txt
├── subdir1
│ ├── file2.txt
│ └── file3.txt
└── subdir2
└── file4.txt
La directory di backup avrà la seguente struttura:
/path/to/your/backup_directory
├── file1.txt
├── subdir1
│ ├── file2.txt
│ └── file3.txt
└── subdir2
└── file4.txt
Spiegazione del codice
os.makedirs(backup_path, exist_ok=True)
: Crea la directory di backup in modo ricorsivo. Se la directory esiste già, non genera errori grazie aexist_ok=True
.os.path.relpath(dirpath, source)
: Calcola il percorso relativo dalla directory di origine per creare la struttura di directory di backup.shutil.copy2(source_file, backup_file)
: Copia i file, mantenendo anche i metadati come i timestamp.
Punti di attenzione
- Link simbolici:
shutil.copy2
copia i link simbolici come normali file. Se desideri mantenere i link simbolici, dovrai applicare un trattamento speciale. - Capacità del disco: Assicurati che ci sia abbastanza spazio sulla destinazione di backup.
- Permessi di accesso: Verifica di avere i permessi necessari per accedere ai file di origine.
Esempi avanzati
- Effettuare il backup solo di file con una determinata estensione, aggiungendo una condizione come
if filename.endswith(".txt")
. - Registrare un log del backup, scrivendo ogni file copiato in un file di log.
- Eseguire un backup differenziale, copiando solo i file che sono stati modificati, confrontando i timestamp o i valori hash.
Conclusione
In questo articolo, abbiamo esplorato come utilizzare os.walk
in Python per esplorare ricorsivamente una directory e le sue sottodirectory. Abbiamo anche visto vari esempi di utilizzo pratico, come la ricerca di file con estensioni specifiche, la gestione della profondità di esplorazione e l’ignoring di file nascosti. Inoltre, abbiamo esplorato come calcolare la dimensione di una directory e fare backup completi dei file.
Grazie alla flessibilità di os.walk
, puoi automatizzare compiti che coinvolgono operazioni su directory e migliorare significativamente l’efficienza dei tuoi progetti. Approfitta di questa potente funzione per semplificare il lavoro con le directory nei tuoi progetti Python!