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.
Links simbólicos
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.







