os.fwalk no Python: percorra diretórios

Publicado em: 05/09/2026
Tempo de leitura: 5 minutos
Pastas e diretórios representando os.fwalk no Python

os.fwalk é uma função da biblioteca padrão do Python para percorrer árvores de diretórios de forma parecida com os.walk, mas com uma diferença importante: além do caminho, dos subdiretórios e dos arquivos, ela entrega um descritor de arquivo para o diretório atual. Esse detalhe permite combinar a travessia com operações baseadas em dir_fd, reduzindo dependência de caminhos absolutos e ajudando a evitar condições de corrida em tarefas sensíveis.

Em scripts simples, os.walk costuma ser suficiente. Porém, quando o programa precisa inspecionar permissões, remover arquivos, renomear entradas ou abrir itens enquanto outra rotina pode alterar a árvore, trabalhar com o descritor do diretório torna a lógica mais robusta. O recurso é especialmente útil em ferramentas de administração, scanners, rotinas de limpeza, empacotadores e serviços que lidam com muitos arquivos.

Como os.fwalk funciona

A assinatura básica é semelhante a os.walk:

import os

for raiz, diretorios, arquivos, fd_raiz in os.fwalk("dados"):
    print(raiz, fd_raiz)
    for nome in arquivos:
        print("arquivo:", nome)

A cada iteração, a função retorna quatro valores: o caminho atual, a lista de diretórios, a lista de arquivos e o descritor do diretório atual. Esse descritor pode ser passado a funções como os.stat, os.open, os.unlink e os.rename por meio do argumento dir_fd.

Por que usar descritores de diretório

Considere uma rotina que monta um caminho com os.path.join, verifica o arquivo e depois o remove. Entre a verificação e a remoção, outro processo pode substituir uma parte do caminho. Esse intervalo cria uma condição de corrida do tipo TOCTOU, abreviação de “time of check to time of use”. Operações relativas a um descritor já aberto diminuem esse risco porque resolvem o nome dentro de um diretório específico.

import os

for raiz, _, arquivos, fd_raiz in os.fwalk("temporarios"):
    for nome in arquivos:
        info = os.stat(nome, dir_fd=fd_raiz, follow_symlinks=False)
        if info.st_size == 0:
            os.unlink(nome, dir_fd=fd_raiz)

O exemplo remove arquivos vazios sem construir o caminho completo para cada operação. O nome é resolvido em relação ao descritor do diretório atual.

O descritor é temporário

O descritor retornado por os.fwalk é válido somente até a próxima etapa da iteração. Não o armazene para uso posterior sem duplicá-lo. Quando precisar conservar o acesso, use os.dup e feche a cópia ao terminar.

import os

for raiz, _, _, fd_raiz in os.fwalk("dados"):
    copia = os.dup(fd_raiz)
    try:
        print(os.listdir(copia))
    finally:
        os.close(copia)

Fechar descritores é obrigatório. Vazamentos podem esgotar o limite do processo e causar falhas difíceis de diagnosticar.

Top-down e bottom-up

Assim como os.walk, a função aceita topdown=True por padrão. Nesse modo, o diretório pai aparece antes dos filhos e a lista diretorios pode ser alterada para podar a busca.

import os

for raiz, diretorios, arquivos, fd_raiz in os.fwalk("projeto", topdown=True):
    diretorios[:] = [d for d in diretorios if d not in {".git", ".venv", "__pycache__"}]
    print(raiz, len(arquivos))

Com topdown=False, os filhos são visitados antes do pai. Esse modo é apropriado para apagar árvores, pois os arquivos e subdiretórios precisam ser removidos antes do diretório superior.

Removendo uma árvore com cuidado

import os

base = "saida-antiga"
for raiz, diretorios, arquivos, fd_raiz in os.fwalk(base, topdown=False):
    for nome in arquivos:
        os.unlink(nome, dir_fd=fd_raiz)
    for nome in diretorios:
        os.rmdir(nome, dir_fd=fd_raiz)
os.rmdir(base)

Esse código é educativo. Em produção, valide rigorosamente a raiz, trate permissões, links simbólicos e erros parciais. Nunca aceite um caminho destrutivo diretamente de entrada não confiável.

O parâmetro follow_symlinks controla se links para diretórios serão seguidos. O padrão é False, opção mais segura. Seguir links pode criar ciclos ou levar a travessia para fora da árvore esperada. Se o recurso for indispensável, registre diretórios visitados por dispositivo e inode para detectar repetições.

Também prefira follow_symlinks=False em chamadas como os.stat quando a intenção for inspecionar o próprio link. A política deve ser explícita em scanners e ferramentas administrativas.

Tratamento de erros

Diretórios podem desaparecer, permissões podem mudar e arquivos podem ser bloqueados durante a travessia. Use onerror para registrar falhas de leitura e exceções específicas ao manipular entradas.

import os

def registrar(erro):
    print(f"Falha em {erro.filename}: {erro}")

for raiz, _, arquivos, fd_raiz in os.fwalk("dados", onerror=registrar):
    for nome in arquivos:
        try:
            info = os.stat(nome, dir_fd=fd_raiz, follow_symlinks=False)
        except FileNotFoundError:
            continue
        except PermissionError as erro:
            registrar(erro)
        else:
            print(raiz, nome, info.st_size)

Comparação com pathlib e os.walk

pathlib.Path.rglob oferece uma API expressiva e é excelente para automações comuns. os.walk é portátil, conhecido e simples para percorrer árvores. os.fwalk se destaca quando operações relativas a descritores são parte central da solução. Ele não deve ser escolhido apenas por parecer mais avançado.

Em plataformas sem suporte completo a dir_fd, a portabilidade pode ser limitada. Verifique os.supports_dir_fd e teste no sistema operacional alvo.

import os

if os.stat in os.supports_dir_fd:
    print("os.stat aceita dir_fd")

Exemplo: inventário seguro

import os
from dataclasses import dataclass

@dataclass
class Item:
    caminho: str
    tamanho: int
    modo: int

def inventario(base: str) -> list[Item]:
    resultado = []
    for raiz, diretorios, arquivos, fd_raiz in os.fwalk(base, follow_symlinks=False):
        diretorios[:] = [d for d in diretorios if d != ".git"]
        for nome in arquivos:
            try:
                info = os.stat(nome, dir_fd=fd_raiz, follow_symlinks=False)
            except (FileNotFoundError, PermissionError):
                continue
            resultado.append(Item(os.path.join(raiz, nome), info.st_size, info.st_mode))
    return resultado

A função separa a travessia da representação do resultado, ignora mudanças transitórias e não segue links. Para árvores enormes, em vez de acumular uma lista, transforme a rotina em gerador e envie cada item para um banco, arquivo ou fila.

Desempenho e limites

os.fwalk não elimina o custo do sistema de arquivos. Chamadas como stat continuam envolvendo o sistema operacional. Evite coletar metadados desnecessários e pode a busca cedo. Em armazenamento remoto, o número de chamadas costuma importar mais que micro-otimizações no Python.

Concorrência também exige critério. Muitos workers podem sobrecarregar discos e servidores de arquivos. Para tarefas de I/O, limite o paralelismo e preserve uma política clara de erros, retomada e idempotência.

Boas práticas

Use uma raiz validada, mantenha follow_symlinks=False por padrão, não retenha o descritor sem os.dup, feche cópias em finally, trate desaparecimento de arquivos como evento normal e teste permissões insuficientes. Em operações destrutivas, ofereça modo de simulação e registre cada ação.

Consulte também os guias da Academify sobre pathlib no Python, módulo os, shutil e contextlib. As referências externas principais são a documentação oficial de os.fwalk e a seção de arquivos e diretórios do módulo os.

Conclusão

os.fwalk combina a conveniência da travessia recursiva com descritores de diretório. Essa abordagem melhora o controle sobre operações relativas, reduz algumas condições de corrida e pode tornar ferramentas de sistema mais seguras. Para automações comuns, APIs mais simples continuam adequadas; para manipulação cuidadosa de árvores mutáveis, os.fwalk é uma opção poderosa da biblioteca padrão.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Desenvolvedor revisando código Python e métodos sobrescritos
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    typing.override: valide sobrescritas de métodos

    Aprenda typing.override no Python para validar sobrescritas, assinaturas, refatorações e contratos de herança com análise estática.

    Ler mais

    Tempo de leitura: 5 minutos
    05/09/2026
    Desenvolvedor trabalhando com filas e threads em Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    queue.SimpleQueue: fila FIFO segura entre threads

    Aprenda queue.SimpleQueue no Python para criar filas FIFO seguras entre threads, organizar workers e evitar erros de concorrência.

    Ler mais

    Tempo de leitura: 5 minutos
    04/09/2026
    Desenvolvedor trabalhando com enums e código Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    StrEnum no Python: enums como strings

    Aprenda StrEnum no Python para criar enums como strings, validar entradas, serializar JSON e organizar APIs e configurações.

    Ler mais

    Tempo de leitura: 4 minutos
    04/09/2026
    Pastas e diretórios para contextlib.chdir no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    contextlib.chdir: restaure o diretório automaticamente

    Aprenda contextlib.chdir no Python para trocar diretórios temporariamente com segurança, testes confiáveis e restauração automática do caminho.

    Ler mais

    Tempo de leitura: 5 minutos
    03/09/2026
    Monitoramento de desempenho e execução de código Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sys.monitoring: instrumentação de baixo overhead

    Aprenda sys.monitoring no Python para instrumentar execução com baixo overhead, eventos, callbacks, ferramentas e observabilidade segura.

    Ler mais

    Tempo de leitura: 6 minutos
    03/09/2026
    Desenvolvedor organizando dados com operator.attrgetter no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    operator.attrgetter: ordene objetos por atributos

    Aprenda operator.attrgetter no Python para ordenar, agrupar e transformar objetos por atributos simples ou aninhados com código mais claro.

    Ler mais

    Tempo de leitura: 5 minutos
    02/09/2026