Como usar os os.walk em Python para percorrer diretórios de forma recursiva

O os.walk do Python é uma ferramenta poderosa para percorrer diretórios e seus conteúdos de forma recursiva. Usando essa função, você pode obter de maneira eficiente todos os subdiretórios e arquivos de um diretório especificado. Neste artigo, vamos explorar desde o uso básico do os.walk até exemplos práticos de aplicação, permitindo que você realize tarefas envolvendo manipulação de diretórios de forma mais eficiente.

Índice

O que é o os.walk?


os.walk é uma função incluída no módulo os da biblioteca padrão do Python, que percorre recursivamente o diretório especificado e gera uma lista dos arquivos e subdiretórios dentro desse diretório. Usando essa função, você pode explorar facilmente estruturas de diretórios complexas e obter uma lista de arquivos ou pastas de forma muito útil.

Como o os.walk funciona


os.walk funciona como um gerador, retornando uma tupla contendo três elementos:

  1. Caminho do diretório (dirpath)
    O caminho do diretório atual sendo explorado.
  2. Lista de subdiretórios (dirnames)
    A lista de nomes dos subdiretórios no diretório atual.
  3. Lista de arquivos (filenames)
    A lista de nomes de arquivos no diretório atual.

Características

  • Exploração recursiva: Explora automaticamente os subdiretórios do diretório especificado.
  • Ordem: É possível configurar o processamento do diretório hierárquico de cima para baixo ou de baixo para cima (topdown=True/False).
  • Eficiência: Gera as informações necessárias no momento, tornando o uso de memória mais eficiente.

Usos

  • Busca por nomes de arquivos
  • Criar uma lista de arquivos com uma extensão específica
  • Cálculo do tamanho dos subdiretórios
  • Automatização de tarefas de backup ou movimentação

Como usar o os.walk

Usando o os.walk, é fácil obter todos os arquivos e pastas dentro de um diretório especificado. Abaixo está um exemplo de código básico.

Exemplo de código

import os

# Especificar o diretório alvo
target_directory = "/path/to/your/directory"

# Usar os.walk para percorrer o diretório
for dirpath, dirnames, filenames in os.walk(target_directory):
    print(f"Caminho Atual: {dirpath}")
    print(f"Subdiretórios: {dirnames}")
    print(f"Arquivos: {filenames}")
    print("-" * 40)

Exemplo de Saída


Suponha que a estrutura do diretório seja a seguinte:

/path/to/your/directory
├── file1.txt
├── file2.txt
├── subdir1
│   └── file3.txt
└── subdir2
    └── file4.txt

Quando o os.walk for executado, ele retornará a seguinte saída:

Caminho Atual: /path/to/your/directory
Subdiretórios: ['subdir1', 'subdir2']
Arquivos: ['file1.txt', 'file2.txt']
----------------------------------------
Caminho Atual: /path/to/your/directory/subdir1
Subdiretórios: []
Arquivos: ['file3.txt']
----------------------------------------
Caminho Atual: /path/to/your/directory/subdir2
Subdiretórios: []
Arquivos: ['file4.txt']
----------------------------------------

Explicação

  • dirpath: O caminho do diretório que está sendo explorado.
  • dirnames: A lista de subdiretórios no diretório atual.
  • filenames: A lista de arquivos no diretório atual.

Cuidados


os.walk gera um erro se o diretório especificado não existir, por isso é recomendado verificar a existência do diretório antes de usá-lo.

Tratamento Diferenciado para Arquivos e Diretórios

Usando o os.walk, é possível classificar eficientemente os arquivos e pastas no diretório. Caso queira aplicar um tratamento diferente para cada tipo, basta adicionar uma lógica de ramificação.

Exemplo de código


Abaixo está um exemplo de código que trata arquivos e subdiretórios de maneira distinta:

import os

# Especificar o diretório alvo
target_directory = "/path/to/your/directory"

# Percorrer o diretório e aplicar ramificação
for dirpath, dirnames, filenames in os.walk(target_directory):
    # Processar os subdiretórios
    for dirname in dirnames:
        subdir_path = os.path.join(dirpath, dirname)
        print(f"Diretório: {subdir_path}")

    # Processar os arquivos
    for filename in filenames:
        file_path = os.path.join(dirpath, filename)
        print(f"Arquivo: {file_path}")

Exemplo de Saída


Suponha que a estrutura do diretório seja a seguinte:

/path/to/your/directory
├── file1.txt
├── file2.txt
├── subdir1
│   └── file3.txt
└── subdir2
    └── file4.txt

A saída será a seguinte:

Diretório: /path/to/your/directory/subdir1
Diretório: /path/to/your/directory/subdir2
Arquivo: /path/to/your/directory/file1.txt
Arquivo: /path/to/your/directory/file2.txt
Arquivo: /path/to/your/directory/subdir1/file3.txt
Arquivo: /path/to/your/directory/subdir2/file4.txt

Explicação do Código

  • os.path.join: Combina dirpath com dirname ou filename para gerar o caminho absoluto.
  • Processamento de subdiretórios (for dirname in dirnames): Permite aplicar operações específicas nos subdiretórios (por exemplo, obter a data de criação do diretório).
  • Processamento de arquivos (for filename in filenames): Permite aplicar operações específicas nos arquivos (por exemplo, obter o tamanho de um arquivo).

Exemplos Avançados

  • Criar e gerenciar uma lista de subdiretórios.
  • Extrair e processar arquivos que sigam uma convenção de nome específica.
  • Filtragem de arquivos com base no tamanho ou data de criação.

Como buscar arquivos com uma extensão específica

Usando os.walk, é fácil buscar arquivos com uma extensão específica. Isso permite, por exemplo, buscar arquivos com a extensão .txt ou .jpg de maneira eficiente.

Exemplo de código


Abaixo está um exemplo de código que busca arquivos com a extensão .txt e imprime seu caminho:

import os

# Especificar o diretório alvo
target_directory = "/path/to/your/directory"

# Especificar a extensão para busca
target_extension = ".txt"

# Buscar arquivos com a extensão especificada
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"Encontrado: {file_path}")

Exemplo de Saída


Suponha que a estrutura do diretório seja a seguinte:

/path/to/your/directory
├── file1.txt
├── file2.doc
├── subdir1
│   └── notes.txt
└── subdir2
    └── image.png

A saída será a seguinte:

Encontrado: /path/to/your/directory/file1.txt
Encontrado: /path/to/your/directory/subdir1/notes.txt

Explicação do Código

  • filename.endswith(target_extension): Retorna True se o nome do arquivo terminar com a extensão especificada. Usado para filtrar arquivos com uma extensão específica.
  • os.path.join: Usado para gerar o caminho completo do arquivo.

Buscando múltiplas extensões


Se você quiser buscar por arquivos com várias extensões, pode alterar a condição para verificar várias extensões de uma vez.

# Especificar múltiplas extensões em uma 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"Encontrado: {file_path}")

Exemplo de Aplicação

  • Obter uma lista de arquivos de código-fonte dentro de um projeto (por exemplo, arquivos .py).
  • Buscar por imagens específicas, como .jpg ou .png, para processamento em lote.
  • Gerar estatísticas sobre arquivos por tipo de extensão.

Limitar a profundidade da busca no diretório

os.walk percorre recursivamente todos os níveis de subdiretórios abaixo do diretório especificado. Porém, em alguns casos, você pode querer limitar a profundidade da busca a um número específico de níveis. Isso pode ser feito controlando a profundidade atual e limitando a exploração dos subdiretórios.

Exemplo de código


O código abaixo limita a profundidade da busca a 2 níveis:

import os

# Especificar o diretório alvo
target_directory = "/path/to/your/directory"

# Especificar a profundidade máxima de busca
max_depth = 2

# Limitar a profundidade da busca
for dirpath, dirnames, filenames in os.walk(target_directory):
    # Calcular a profundidade atual
    current_depth = dirpath.count(os.sep) - target_directory.count(os.sep) + 1

    if current_depth > max_depth:
        # Se a profundidade for maior que o limite, ignore os subdiretórios
        del dirnames[:]  # Limpa a lista de subdiretórios para ignorá-los
        continue

    print(f"Profundidade {current_depth}: {dirpath}")
    print(f"Subdiretórios: {dirnames}")
    print(f"Arquivos: {filenames}")
    print("-" * 40)

Exemplo de Saída


Suponha que a estrutura do diretório seja a seguinte:

/path/to/your/directory
├── file1.txt
├── subdir1
│   ├── file2.txt
│   └── subsubdir1
│       └── file3.txt
└── subdir2
    └── file4.txt

Com a profundidade limitada a 2, a saída será:

Profundidade 1: /path/to/your/directory
Subdiretórios: ['subdir1', 'subdir2']
Arquivos: ['file1.txt']
----------------------------------------
Profundidade 2: /path/to/your/directory/subdir1
Subdiretórios: ['subsubdir1']
Arquivos: ['file2.txt']
----------------------------------------
Profundidade 2: /path/to/your/directory/subdir2
Subdiretórios: []
Arquivos: ['file4.txt']
----------------------------------------

Explicação do Código

  • os.sep: Obtém o separador de diretório dependente do sistema operacional (no Windows é \\, no Unix é /).
  • dirpath.count(os.sep): Conta o número de separadores no caminho do diretório atual para calcular a profundidade.
  • del dirnames[:]: Limpa a lista de subdiretórios para ignorar a exploração dos diretórios de maior profundidade.

Exemplos de Aplicação

  • Percorrer apenas os diretórios de nível superior em um projeto de grande escala.
  • Exibir parte da árvore de diretórios com limite de profundidade.
  • Reduzir a carga nas operações de disco, realizando buscas limitadas.

Ignorando arquivos e pastas ocultas

Durante a busca de diretórios, você pode querer ignorar arquivos e pastas ocultos (geralmente aqueles cujo nome começa com .). Usando os.walk, é possível filtrar os elementos ocultos, tornando a operação mais eficiente.

Exemplo de código


Abaixo está um exemplo de código para ignorar arquivos e pastas ocultas durante a exploração do diretório:

import os

# Especificar o diretório alvo
target_directory = "/path/to/your/directory"

# Ignorar arquivos e pastas ocultas
for dirpath, dirnames, filenames in os.walk(target_directory):
    # Ignorar pastas ocultas
    dirnames[:] = [d for d in dirnames if not d.startswith(".")]

    # Ignorar arquivos ocultos
    visible_files = [f for f in filenames if not f.startswith(".")]

    print(f"Caminho Atual: {dirpath}")
    print(f"Subdiretórios: {dirnames}")
    print(f"Arquivos: {visible_files}")
    print("-" * 40)

Exemplo de Saída


Se a estrutura do diretório for a seguinte:

/path/to/your/directory
├── file1.txt
├── .hidden_file.txt
├── subdir1
│   ├── file2.txt
│   └── .hidden_folder
│       └── file3.txt
└── subdir2
    └── file4.txt

Ignorando arquivos e pastas ocultas, a saída será:

Caminho Atual: /path/to/your/directory
Subdiretórios: ['subdir1', 'subdir2']
Arquivos: ['file1.txt']
----------------------------------------
Caminho Atual: /path/to/your/directory/subdir1
Subdiretórios: []
Arquivos: ['file2.txt']
----------------------------------------
Caminho Atual: /path/to/your/directory/subdir2
Subdiretórios: []
Arquivos: ['file4.txt']
----------------------------------------

Explicação do Código

  • Ignorando pastas ocultas (dirnames[:] = ...): Sobrescreve dirnames para excluir pastas cujo nome começa com .. Isso impede a exploração desses subdiretórios.
  • Ignorando arquivos ocultos ([f for f in filenames ...]): Usando list comprehension para filtrar arquivos cujo nome começa com ..

Cuidados

  • Se arquivos ou pastas estiverem configurados como ocultos no sistema (particularmente no Windows), esse código não será capaz de detectá-los. Nesse caso, pode ser necessário usar módulos adicionais, como ctypes.

Exemplos de Aplicação

  • Excluir arquivos de configuração ocultos, como .gitignore ou .env, durante o processamento.
  • Criar uma lista de diretórios para exibição ao usuário, ignorando pastas ocultas.
  • Excluir elementos ocultos ao limpar grandes conjuntos de dados.

Exemplo Prático: Cálculo do Tamanho de um Diretório

Usando os.walk, você pode somar o tamanho de todos os arquivos em um diretório especificado para calcular o tamanho total do diretório. Esse método é útil para verificar quanto espaço de armazenamento um diretório específico está consumindo.

Exemplo de código


Abaixo está um exemplo de código para calcular o tamanho de um diretório:

import os

# Especificar o diretório alvo
target_directory = "/path/to/your/directory"

def calculate_directory_size(directory):
    total_size = 0
    # Percorrer o diretório
    for dirpath, dirnames, filenames in os.walk(directory):
        for filename in filenames:
            file_path = os.path.join(dirpath, filename)
            try:
                # Obter e somar o tamanho do arquivo
                total_size += os.path.getsize(file_path)
            except FileNotFoundError:
                # Tratamento de exceção caso o arquivo tenha sido deletado
                pass
    return total_size

# Calcular o tamanho do diretório
directory_size = calculate_directory_size(target_directory)

# Exibir o resultado (em bytes e em MB)
print(f"Tamanho do Diretório: {directory_size} bytes")
print(f"Tamanho do Diretório: {directory_size / (1024 ** 2):.2f} MB")

Exemplo de Saída


Se a estrutura do diretório for a seguinte:

/path/to/your/directory
├── file1.txt (500 bytes)
├── subdir1
│   ├── file2.txt (1500 bytes)
│   └── file3.txt (3000 bytes)
└── subdir2
    └── file4.txt (2000 bytes)

O resultado da execução será:

Tamanho do Diretório: 7000 bytes  
Tamanho do Diretório: 0.01 MB  

Explicação do Código

  • os.path.getsize(file_path): Obtém o tamanho do arquivo em bytes.
  • Tratamento de exceção: Captura a exceção FileNotFoundError caso o arquivo seja deletado ou inacessível durante a execução.
  • Conversão de unidades: Converte o tamanho do arquivo de bytes para um formato mais legível (KB, MB, etc.).

Exemplo Prático: Calcular o Tamanho de Arquivos com uma Extensão Específica


Se você quiser calcular o tamanho total de arquivos com uma extensão específica, como .txt, o código pode ser ajustado da seguinte forma:

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

# Exemplo: Calcular o tamanho total dos arquivos .txt
txt_size = calculate_size_by_extension(target_directory, ".txt")
print(f"Tamanho dos Arquivos .txt: {txt_size} bytes")

Praticidade

  • Monitoramento do uso de disco em servidores ou armazenamento em nuvem.
  • Obter recursos consumidos por pastas de projetos específicos.
  • Apoiar o trabalho de limpeza de dados em caso de falta de espaço em disco.

Exemplo Prático: Criar Cópia de Backup de Todos os Arquivos

Usando os.walk, você pode percorrer recursivamente todos os arquivos em um diretório e copiá-los para um diretório de backup, criando uma cópia de segurança completa do diretório. Esse método é útil para copiar dados de maneira segura, mantendo a estrutura de diretórios.

Exemplo de código


Abaixo está um exemplo de código que copia arquivos para um diretório de backup:

import os
import shutil

# Especificar o diretório original e o diretório de 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):
        # Calcular o caminho de backup
        relative_path = os.path.relpath(dirpath, source)
        backup_path = os.path.join(backup, relative_path)

        # Criar diretório de backup
        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:
                # Copiar arquivo
                shutil.copy2(source_file, backup_file)
                print(f"Copiado: {source_file} -> {backup_file}")
            except Exception as e:
                print(f"Falha ao copiar {source_file}: {e}")

# Executar o backup
backup_files(source_directory, backup_directory)

Exemplo de Saída


Se a estrutura do diretório for a seguinte:

/path/to/your/source_directory
├── file1.txt
├── subdir1
│   ├── file2.txt
│   └── file3.txt
└── subdir2
    └── file4.txt

A estrutura será copiada para o diretório de backup:

/path/to/your/backup_directory
├── file1.txt
├── subdir1
│   ├── file2.txt
│   └── file3.txt
└── subdir2
    └── file4.txt

Explicação do Código

  • os.makedirs(backup_path, exist_ok=True): Cria o diretório de backup recursivamente, sem gerar erro caso o diretório já exista.
  • os.path.relpath(dirpath, source): Obtém o caminho relativo do diretório original para construir o caminho de backup.
  • shutil.copy2(source_file, backup_file): Copia o arquivo, incluindo seus metadados como o timestamp.

Cuidados

  1. Links simbólicos: O shutil.copy2 copia links simbólicos como arquivos normais. Se você deseja preservar o link, será necessário um tratamento especial.
  2. Espaço em disco: Certifique-se de que o diretório de backup tenha espaço suficiente para os dados.
  3. Permissões de acesso: Você precisará de permissões de acesso para copiar os arquivos.

Exemplos de Aplicação

  • Backup de arquivos com uma extensão específica: Adicionar a condição if filename.endswith(".txt") no código.
  • Gravar um log de backup: Registrar os arquivos copiados em um arquivo de log.
  • Backup incremental: Comparar timestamps ou valores de hash dos arquivos para copiar apenas os arquivos modificados.

Conclusão

Neste artigo, exploramos como usar o os.walk para percorrer diretórios de forma recursiva e exemplos práticos de como utilizá-lo em diferentes situações. O os.walk é uma ferramenta poderosa que permite realizar tarefas relacionadas a arquivos e diretórios de forma eficiente.

Desde o uso básico até filtragens específicas, limites de profundidade, exclusão de arquivos ocultos, até a implementação de cálculos de tamanho de diretório e cópia de backup, este artigo cobriu diversos exemplos de aplicação.

Ao aproveitar a flexibilidade do os.walk, você pode automatizar tarefas que envolvem manipulação de diretórios e melhorar significativamente a sua produtividade. Experimente usar o os.walk em seus projetos!

Índice