filecmp no Python: compare arquivos e pastas

Publicado em: 03/08/2026
Tempo de leitura: 7 minutos

Sincronizadores, backups, testes de implantação e ferramentas de auditoria precisam descobrir se arquivos ou árvores de diretórios são iguais. Ler cada byte sempre funciona, mas pode ser caro quando há milhares de itens. O módulo filecmp no Python oferece comparações rápidas entre arquivos, lotes e diretórios, com opção de verificar metadados ou conteúdo real.

Neste guia, você aprenderá a usar cmp(), cmpfiles() e dircmp, entenderá o parâmetro shallow, o cache baseado em stat(), a comparação recursiva e quando complementar o resultado com hashes. O conteúdo se conecta aos artigos sobre difflib, tempfile, leitura de arquivos, PermissionError e collections.

Comparação básica com cmp()

filecmp.cmp() recebe dois caminhos e informa se os arquivos parecem iguais.

from filecmp import cmp

iguais = cmp("original.txt", "copia.txt")
print(iguais)

O valor padrão shallow=True permite considerar iguais arquivos cuja assinatura de os.stat() coincide. Essa assinatura inclui tipo, tamanho e tempo de modificação.

Comparação superficial

A comparação superficial evita abrir o conteúdo quando os metadados já coincidem.

iguais = cmp("a.bin", "b.bin", shallow=True)

É rápida para caches, builds e diretórios controlados, mas não prova que todos os bytes são iguais. Dois arquivos diferentes podem ter o mesmo tamanho e timestamp.

Comparação por conteúdo

Para ler e comparar os bytes, use shallow=False.

iguais = cmp("a.bin", "b.bin", shallow=False)

A documentação oficial de filecmp informa que, mesmo quando shallow=False, a função pode reutilizar um resultado armazenado em cache. O cache é invalidado quando as informações de stat() mudam.

O cache e timestamps rápidos

Em sistemas com baixa resolução de timestamp, um arquivo pode ser alterado rapidamente sem que o tempo de modificação aparente mude. Se tamanho e timestamp também permanecerem iguais, um resultado antigo pode ser reutilizado.

import filecmp

filecmp.clear_cache()
iguais = filecmp.cmp("a.txt", "b.txt", shallow=False)

clear_cache() é útil em testes ou comparações realizadas imediatamente depois de uma gravação. Em fluxos normais, fechar e sincronizar os arquivos antes da comparação reduz ambiguidades.

Verificando que os caminhos são arquivos

cmp() foi projetada para arquivos regulares. Valide entradas antes de comparar.

from pathlib import Path
from filecmp import cmp


def arquivos_iguais(a, b):
    pa = Path(a)
    pb = Path(b)
    if not pa.is_file() or not pb.is_file():
        raise ValueError("Os dois caminhos devem ser arquivos")
    return cmp(pa, pb, shallow=False)

Links simbólicos, dispositivos e arquivos especiais exigem uma política própria. Decida se deseja comparar o link, o alvo ou rejeitar o item.

Comparando vários nomes com cmpfiles()

cmpfiles() compara arquivos com nomes relativos iguais em dois diretórios.

from filecmp import cmpfiles

nomes = ["app.py", "config.toml", "README.md"]
iguais, diferentes, erros = cmpfiles(
    "versao-a",
    "versao-b",
    nomes,
    shallow=False,
)

print("Iguais:", iguais)
print("Diferentes:", diferentes)
print("Erros:", erros)

A terceira lista contém arquivos ausentes, inválidos ou que não puderam ser lidos. Não trate erro como simples diferença; registre e investigue a causa.

Tratando PermissionError e arquivos ausentes

Comparações podem falhar por permissões, links quebrados ou concorrência.

from pathlib import Path

for nome in erros:
    caminho_a = Path("versao-a") / nome
    caminho_b = Path("versao-b") / nome
    print(nome, caminho_a.exists(), caminho_b.exists())

Uma aplicação de auditoria deve diferenciar ausente, sem permissão, tipo incompatível e alteração durante a leitura.

Analisando diretórios com dircmp

A classe dircmp compara duas árvores e expõe listas e subcomparações.

from filecmp import dircmp

comparacao = dircmp("projeto-a", "projeto-b")
print(comparacao.left_only)
print(comparacao.right_only)
print(comparacao.common_files)
print(comparacao.diff_files)

Os atributos são calculados sob demanda, então criar o objeto não percorre necessariamente toda a árvore.

Principais atributos de dircmp

  • left_list e right_list: entradas de cada lado;
  • common: nomes presentes em ambos;
  • left_only e right_only: nomes exclusivos;
  • common_dirs: subdiretórios em comum;
  • common_files: arquivos regulares em comum;
  • common_funny: itens com tipos incompatíveis ou erro de stat();
  • same_files, diff_files e funny_files: resultados da comparação de arquivos comuns.

Use todas as categorias relevantes; verificar apenas diff_files pode ignorar arquivos exclusivos.

Relatórios prontos

report() mostra apenas o nível atual. report_partial_closure() inclui subdiretórios comuns imediatos. report_full_closure() percorre recursivamente.

comparacao.report_full_closure()

Esses métodos imprimem em saída padrão. Para aplicações web, JSON ou testes, leia os atributos e construa uma estrutura própria.

Recursão com subdirs

subdirs mapeia cada subdiretório comum para outro objeto dircmp.

def coletar(comp, prefixo=""):
    resultado = []
    for nome in comp.left_only:
        resultado.append(("somente_esquerda", prefixo + nome))
    for nome in comp.right_only:
        resultado.append(("somente_direita", prefixo + nome))
    for nome in comp.diff_files:
        resultado.append(("diferente", prefixo + nome))
    for nome, sub in comp.subdirs.items():
        resultado.extend(coletar(sub, prefixo + nome + "/"))
    return resultado

Proteja a aplicação contra árvores enormes, profundidade excessiva e alterações concorrentes.

shallow em dircmp

Desde Python 3.13, dircmp aceita o argumento shallow.

comparacao = dircmp("a", "b", shallow=False)

Use False quando same_files e diff_files precisam refletir conteúdo, não apenas metadados.

Ignorando nomes

O parâmetro ignore substitui a lista padrão de nomes ignorados.

comparacao = dircmp(
    "a",
    "b",
    ignore=[".git", "__pycache__", ".venv", "node_modules"],
    shallow=False,
)

Se você fornece a lista, inclua também o que deseja manter ignorado. Não esconda artefatos relevantes por conveniência.

O parâmetro hide

hide controla nomes omitidos dos relatórios, com padrão incluindo . e ...

Em geral, ignore define itens que não participam da comparação, enquanto hide afeta a apresentação.

Comparação textual com difflib

filecmp informa que dois arquivos diferem, mas não explica como. Para texto, gere um diff depois.

from difflib import unified_diff
from pathlib import Path

antes = Path("a/config.ini").read_text(encoding="utf-8").splitlines(True)
depois = Path("b/config.ini").read_text(encoding="utf-8").splitlines(True)

print("".join(unified_diff(antes, depois, fromfile="a", tofile="b")))

Em arquivos binários, um diff de linhas não faz sentido; reporte tamanho, hash ou uma ferramenta específica do formato.

Quando usar hashes

Uma comparação byte a byte responde se o conteúdo atual coincide. Um hash persistido permite verificar integridade em outro momento ou máquina.

from hashlib import file_digest


def sha256(caminho):
    with open(caminho, "rb") as arquivo:
        return file_digest(arquivo, "sha256").hexdigest()

A documentação oficial de hashlib disponibiliza SHA-256 e outros algoritmos. Para segurança, evite MD5 e SHA-1 em novas verificações contra adulteração.

Hash não elimina a leitura

Calcular um digest lê todos os bytes e normalmente custa mais que uma comparação que pode parar na primeira diferença. Use hashes quando precisa armazenar, transmitir ou assinar uma impressão digital, não apenas para comparar dois arquivos locais uma única vez.

Condições de corrida

Um arquivo pode mudar entre stat(), leitura e geração do relatório. O resultado descreve um momento aproximado, não um snapshot transacional.

Para backups críticos, trabalhe sobre snapshots do sistema de arquivos, bloqueios apropriados ou cópias temporárias. Depois da comparação, verifique novamente metadados se a consistência for essencial.

A resolução de links depende das operações de sistema utilizadas. Uma ferramenta de sincronização precisa definir se preserva links ou compara alvos.

Use Path.is_symlink() e os.readlink() quando a identidade do link importa. Evite seguir links para fora da raiz autorizada.

Arquivos grandes

cmp(..., shallow=False) lê em blocos e não precisa carregar o arquivo inteiro na memória. Mesmo assim, comparar muitos arquivos grandes consome I/O.

Use metadados como filtro inicial, limite concorrência para não saturar o disco e priorize arquivos modificados. Em armazenamento remoto, considere APIs de checksum fornecidas pelo serviço.

Testes com diretórios temporários

from pathlib import Path
from tempfile import TemporaryDirectory
from filecmp import dircmp

with TemporaryDirectory() as a, TemporaryDirectory() as b:
    Path(a, "igual.txt").write_text("ok", encoding="utf-8")
    Path(b, "igual.txt").write_text("ok", encoding="utf-8")
    Path(a, "diferente.txt").write_text("A", encoding="utf-8")
    Path(b, "diferente.txt").write_text("B", encoding="utf-8")

    comp = dircmp(a, b, shallow=False)
    assert "igual.txt" in comp.same_files
    assert "diferente.txt" in comp.diff_files

Inclua arquivos exclusivos, subdiretórios, erros de permissão, links e alterações rápidas.

Exemplo de auditoria estruturada

def auditar(a, b):
    comp = dircmp(a, b, shallow=False)
    return {
        "somente_a": comp.left_only,
        "somente_b": comp.right_only,
        "iguais": comp.same_files,
        "diferentes": comp.diff_files,
        "erros": comp.funny_files + comp.common_funny,
        "subdiretorios": {
            nome: auditar(sub.left, sub.right)
            for nome, sub in comp.subdirs.items()
        },
    }

Em árvores não confiáveis, imponha limite de profundidade e quantidade de itens.

Erros frequentes

  • Usar shallow=True como prova criptográfica de igualdade.
  • Ignorar left_only e right_only.
  • Tratar arquivos com erro como diferentes comuns.
  • Esquecer o cache após gravações muito rápidas.
  • Comparar links simbólicos sem definir a política.
  • Calcular hash para tudo sem considerar custo.
  • Presumir que a árvore não muda durante a análise.
  • Imprimir relatórios quando a aplicação precisa de dados estruturados.

Boas práticas

  • Escolha conscientemente comparação superficial ou por conteúdo.
  • Use cmpfiles() para lotes com nomes conhecidos.
  • Use dircmp para estrutura e recursão.
  • Classifique ausências, diferenças e erros separadamente.
  • Use difflib para explicar diferenças textuais.
  • Use SHA-256 quando precisa de uma impressão digital persistente.
  • Limite profundidade, número de arquivos e concorrência.
  • Teste alterações rápidas e comportamento multiplataforma.

Conclusão

O módulo filecmp no Python fornece uma base simples para comparar arquivos e diretórios. cmp() trabalha com dois arquivos, cmpfiles() classifica um lote e dircmp revela diferenças estruturais e recursivas entre árvores.

A confiabilidade depende da opção escolhida. Metadados oferecem velocidade; conteúdo oferece uma confirmação mais forte; hashes permitem persistir uma impressão digital. Ao separar diferenças de erros, considerar o cache, definir políticas para links e lidar com concorrência, você pode construir verificadores de implantação, backups e auditorias que produzem resultados claros sem ler mais dados do que o necessário.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Terminal de comandos representando parsing seguro com shlex no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    shlex no Python: comandos e argumentos seguros

    Aprenda shlex no Python para separar comandos, tratar aspas, usar quote e join e reduzir riscos de injeção ao executar

    Ler mais

    Tempo de leitura: 7 minutos
    02/08/2026
    Banco de dados local representando persistência com shelve no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    shelve no Python: persistência simples

    Aprenda shelve no Python para persistir objetos, atualizar dados mutáveis, evitar riscos de pickle e saber quando migrar para SQLite.

    Ler mais

    Tempo de leitura: 5 minutos
    01/08/2026
    Documentos de texto representando comparação de versões com difflib no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    difflib no Python: compare textos e arquivos

    Aprenda difflib no Python para comparar textos, medir similaridade, criar diffs unificados, relatórios HTML e sugestões de nomes.

    Ler mais

    Tempo de leitura: 7 minutos
    01/08/2026
    Painel de gráficos representando análise estatística de dados no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    statistics no Python: análise de dados

    Aprenda statistics no Python para média, mediana, desvio padrão, quantis, correlação, regressão, NormalDist e KDE.

    Ler mais

    Tempo de leitura: 8 minutos
    31/07/2026
    Gráficos de frações representando números racionais exatos no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    fractions no Python: números racionais

    Aprenda fractions no Python para cálculos racionais exatos, simplificação, limit_denominator, formatação e conversões seguras.

    Ler mais

    Tempo de leitura: 7 minutos
    31/07/2026
    Calculadora e documentos representando cálculos decimais precisos no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    Decimal no Python: cálculos precisos

    Aprenda Decimal no Python para cálculos exatos, dinheiro, quantize, arredondamento, contextos e validação sem erros de float.

    Ler mais

    Tempo de leitura: 8 minutos
    30/07/2026