---
title: "tempfile em Python: arquivos temporários seguros na prática"
url: "https://python.dev.br/blog/python-tempfile-arquivos-temporarios/"
markdown_url: "https://python.dev.br/blog/python-tempfile-arquivos-temporarios.MD"
description: "Aprenda tempfile em Python com TemporaryDirectory, NamedTemporaryFile, SpooledTemporaryFile, testes, permissões e limpeza automática em exemplos práticos."
date: "2026-07-24"
author: "Equipe Python Brasil"
---

# tempfile em Python: arquivos temporários seguros na prática

Aprenda tempfile em Python com TemporaryDirectory, NamedTemporaryFile, SpooledTemporaryFile, testes, permissões e limpeza automática em exemplos práticos.


O módulo `tempfile` é a forma recomendada de criar **arquivos e diretórios temporários em Python** sem inventar nomes, disputar o mesmo caminho com outro processo ou esquecer resíduos no servidor. Ele faz parte da biblioteca padrão e oferece APIs de alto nível como `TemporaryDirectory`, `NamedTemporaryFile`, `TemporaryFile` e `SpooledTemporaryFile`.

A recomendação direta é: use um **context manager (`with`)** sempre que o temporário só for necessário durante uma operação. Escolha `TemporaryDirectory` para fluxos com vários artefatos; `NamedTemporaryFile` quando outra biblioteca precisa receber um caminho; `TemporaryFile` quando apenas seu código usa o objeto de arquivo; e `SpooledTemporaryFile` quando dados pequenos podem ficar em memória, mas os grandes devem migrar automaticamente para o disco.

Isso aparece em tarefas reais como gerar PDFs, descompactar documentos fiscais, converter imagens, preparar anexos, receber uploads e chamar programas externos. Neste guia, você vai aprender as diferenças entre as APIs, as armadilhas no Windows, como testar com `pytest` e como montar um processamento seguro de relatórios.

## Por que não criar um arquivo com nome fixo?

Um script pequeno pode parecer funcionar assim:

```python
from pathlib import Path

caminho = Path("/tmp/relatorio.pdf")
caminho.write_bytes(b"conteudo")
```

O problema aparece quando duas execuções usam `relatorio.pdf` ao mesmo tempo. Uma pode sobrescrever a outra, ler conteúdo incompleto ou apagar um arquivo que ainda está em uso. Em aplicações web, um nome previsível também pode abrir espaço para ataques envolvendo links simbólicos ou troca do arquivo entre a verificação e a abertura.

Acrescentar a data ou um número aleatório manualmente não resolve bem:

```python
# Evite criar sua própria estratégia de nome temporário
caminho = Path(f"/tmp/relatorio-{cliente_id}.pdf")
```

Além de expor identificadores, o nome ainda pode colidir e costuma deixar a responsabilidade de limpeza espalhada pelo código. `tempfile` centraliza esses detalhes, escolhe a pasta temporária adequada ao sistema e cria nomes exclusivos com permissões apropriadas.

> Temporário não significa sem importância. Um arquivo pode conter dados pessoais, notas fiscais, contratos ou credenciais. Trate seu conteúdo com o mesmo cuidado aplicado ao arquivo definitivo.

## TemporaryDirectory: a melhor opção para uma tarefa completa

`TemporaryDirectory` cria uma pasta exclusiva e devolve seu caminho. Ao sair do bloco `with`, o Python remove a pasta e seu conteúdo.

```python
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as pasta:
    temporaria = Path(pasta)
    entrada = temporaria / "entrada.csv"
    saida = temporaria / "relatorio.txt"

    entrada.write_text("pedido,total\n101,199.90\n", encoding="utf-8")
    saida.write_text("Relatório processado", encoding="utf-8")

    print(saida.read_text(encoding="utf-8"))

# A pasta e os dois arquivos já foram removidos aqui
```

A limpeza ocorre mesmo quando uma exceção interrompe a operação, porque o context manager executa sua finalização. Isso torna a API especialmente útil para pipelines com várias etapas:

1. baixar ou receber um documento;
2. extrair arquivos;
3. transformar o conteúdo;
4. enviar apenas o resultado final;
5. descartar os intermediários.

Você pode personalizar o prefixo para facilitar o diagnóstico sem tornar o nome previsível:

```python
with TemporaryDirectory(prefix="nfe-processamento-") as pasta:
    print(pasta)
```

O sistema ainda acrescenta uma parte aleatória. Não dependa do formato exato do nome, pois ele é detalhe de implementação.

### Mantendo o resultado que realmente importa

Tudo dentro da pasta será apagado. Se um artefato precisa sobreviver, copie ou mova-o antes de sair do bloco:

```python
import shutil
from pathlib import Path
from tempfile import TemporaryDirectory

DESTINO = Path("relatorios/relatorio-final.csv")
DESTINO.parent.mkdir(parents=True, exist_ok=True)

with TemporaryDirectory() as pasta:
    temporario = Path(pasta) / "relatorio.csv"
    temporario.write_text("id,status\n1,ok\n", encoding="utf-8")

    shutil.copy2(temporario, DESTINO)
```

O artigo sobre [`zipfile` e `shutil`](/blog/python-zipfile-shutil-comprimir-extrair/) explica quando usar `copy`, `copy2`, `move` e extração segura.

## NamedTemporaryFile: quando você precisa de um caminho

Algumas bibliotecas aceitam um objeto de arquivo. Outras exigem um caminho no sistema, normalmente como `str` ou `Path`. `NamedTemporaryFile` atende ao segundo caso e expõe o nome no atributo `.name`.

```python
from pathlib import Path
from tempfile import NamedTemporaryFile

with NamedTemporaryFile(
    mode="w",
    suffix=".json",
    prefix="pedido-",
    encoding="utf-8",
) as arquivo:
    arquivo.write('{"pedido_id": 101, "status": "aprovado"}')
    arquivo.flush()

    caminho = Path(arquivo.name)
    print(caminho.name)
    print(caminho.read_text(encoding="utf-8"))
```

O `flush()` envia o conteúdo do buffer do Python ao sistema operacional antes que outro leitor abra o caminho. Isso não é a mesma coisa que garantir persistência física em disco, mas normalmente é o necessário para uma biblioteca ler os bytes recém-gravados.

Use `suffix` quando a ferramenta identifica o formato pela extensão, como `.pdf`, `.png` ou `.csv`. O sufixo ajuda na interoperabilidade; ele não valida o conteúdo.

### A armadilha do Windows

Reabrir um `NamedTemporaryFile` enquanto ele continua aberto funciona de maneira diferente entre sistemas. No Windows, o compartilhamento e a exclusão de arquivos abertos seguem regras mais restritivas. Em versões modernas do Python, as opções `delete` e `delete_on_close` permitem controlar quando o nome será removido.

Uma estratégia portátil quando uma ferramenta externa precisa abrir o caminho é fechar o arquivo antes do uso e fazer a limpeza explicitamente:

```python
from pathlib import Path
from tempfile import NamedTemporaryFile

caminho: Path | None = None

try:
    with NamedTemporaryFile(
        mode="wb",
        suffix=".pdf",
        delete=False,
    ) as arquivo:
        arquivo.write(b"%PDF-conteudo-de-exemplo")
        caminho = Path(arquivo.name)

    # A biblioteca ou o subprocesso abre o caminho já fechado.
    print(f"Processar: {caminho}")
finally:
    if caminho is not None:
        caminho.unlink(missing_ok=True)
```

Ao usar `delete=False`, a limpeza passa a ser sua responsabilidade. Mantenha-a em um `finally`, não apenas no caminho de sucesso. Para uma sequência com vários arquivos, `TemporaryDirectory` costuma ser mais simples e menos propenso a vazamentos.

## TemporaryFile: um arquivo privado para a operação

`TemporaryFile` devolve um objeto de arquivo que é removido automaticamente ao fechar. Em alguns sistemas, o arquivo pode nem ter uma entrada de diretório visível. Use-o quando seu código só precisa ler e escrever pelo próprio objeto e ninguém exige um caminho.

```python
from tempfile import TemporaryFile

with TemporaryFile(mode="w+b") as arquivo:
    arquivo.write(b"linha 1\nlinha 2\n")
    arquivo.seek(0)
    conteudo = arquivo.read()

print(conteudo.decode("utf-8"))
```

Após escrever, `seek(0)` reposiciona o cursor no início. Sem isso, `read()` começa no fim e devolve bytes vazios.

Para texto, informe modo e encoding:

```python
from tempfile import TemporaryFile

with TemporaryFile(mode="w+t", encoding="utf-8") as arquivo:
    arquivo.write("São Paulo; aprovado\n")
    arquivo.seek(0)
    print(arquivo.read())
```

Prefira essa API a `NamedTemporaryFile` quando o nome não tem utilidade. Menos componentes conseguem localizar ou manipular o arquivo por caminho.

## SpooledTemporaryFile: memória primeiro, disco depois

`SpooledTemporaryFile` mantém o conteúdo em memória até atingir `max_size`. Depois desse limite — ou se `rollover()` for chamado — ele migra para um arquivo em disco.

```python
from tempfile import SpooledTemporaryFile

with SpooledTemporaryFile(max_size=1_000_000, mode="w+b") as arquivo:
    arquivo.write(b"dados do relatorio")
    arquivo.seek(0)
    enviar_para_api(arquivo.read())
```

Essa opção é útil quando a maioria dos objetos é pequena, mas alguns podem crescer. Você evita acesso desnecessário ao disco nos casos comuns sem correr o risco de manter todo arquivo grande na RAM.

Um exemplo típico é preparar um CSV para upload:

```python
import csv
import io
from tempfile import SpooledTemporaryFile

with SpooledTemporaryFile(max_size=2_000_000, mode="w+b") as binario:
    texto = io.TextIOWrapper(binario, encoding="utf-8", newline="")
    escritor = csv.DictWriter(texto, fieldnames=["pedido", "total"])
    escritor.writeheader()
    escritor.writerows(
        [
            {"pedido": 101, "total": "199,90"},
            {"pedido": 102, "total": "49,00"},
        ]
    )
    texto.flush()
    binario.seek(0)

    payload = binario.read()
    print(len(payload))
```

Não escolha um limite gigantesco sem medir. Em um servidor que processa muitos uploads simultâneos, alguns megabytes por requisição podem virar vários gigabytes de memória. Limites de concorrência e tamanho continuam necessários.

## Como o Python escolhe a pasta temporária?

`tempfile.gettempdir()` mostra o diretório padrão selecionado para a execução:

```python
import tempfile

print(tempfile.gettempdir())
```

O resultado varia conforme sistema operacional e variáveis de ambiente. Em Linux, é comum encontrar `/tmp`; no Windows, uma pasta dentro do perfil do usuário. Não grave lógica de negócio assumindo um caminho específico.

Se você precisa apenas descobrir a localização, `gettempdir()` é suficiente. Se precisa de um arquivo, não monte manualmente `gettempdir() / nome`: use as funções de criação do módulo.

### mkstemp e mkdtemp são APIs de baixo nível

`mkstemp()` e `mkdtemp()` criam recursos com nomes seguros, mas não oferecem limpeza automática. `mkstemp()` ainda devolve um descritor de arquivo que precisa ser fechado.

```python
import os
from pathlib import Path
from tempfile import mkstemp

fd, nome = mkstemp(suffix=".txt")
caminho = Path(nome)

try:
    with os.fdopen(fd, mode="w", encoding="utf-8") as arquivo:
        arquivo.write("resultado")
finally:
    caminho.unlink(missing_ok=True)
```

Na maioria dos projetos, prefira as APIs de alto nível. Use `mkstemp` apenas quando você realmente precisa controlar descritor, abertura e ciclo de vida.

## Exemplo prático: gerar e publicar um relatório sem deixar resíduos

Imagine um serviço que recebe registros, gera um PDF em uma pasta de trabalho, compacta os comprovantes e copia apenas o pacote final para uma área de saída. Em vez de misturar intermediários com arquivos publicados, cada execução ganha uma pasta temporária exclusiva.

```python
import shutil
from pathlib import Path
from tempfile import TemporaryDirectory


def gerar_pdf(registros: list[dict], destino: Path) -> None:
    # Substitua pela biblioteca de PDF usada no projeto.
    linhas = ["RELATÓRIO DE PEDIDOS", ""]
    linhas.extend(
        f"Pedido {item['id']}: R$ {item['total']}"
        for item in registros
    )
    destino.write_text("\n".join(linhas), encoding="utf-8")


def publicar_relatorio(registros: list[dict], saida: Path) -> Path:
    saida.mkdir(parents=True, exist_ok=True)
    pacote_final = saida / "relatorio-pedidos.zip"

    with TemporaryDirectory(prefix="relatorio-pedidos-") as pasta:
        trabalho = Path(pasta)
        artefatos = trabalho / "artefatos"
        artefatos.mkdir()
        pdf = artefatos / "relatorio.pdf"
        metadados = artefatos / "LEIA-ME.txt"

        gerar_pdf(registros, pdf)
        metadados.write_text(
            "Arquivo gerado automaticamente. Valide antes de distribuir.",
            encoding="utf-8",
        )

        base_zip = trabalho / "pacote"
        zip_criado = Path(
            shutil.make_archive(
                str(base_zip),
                format="zip",
                root_dir=artefatos,
                base_dir=".",
            )
        )

        temporario_publicacao = saida / ".relatorio-pedidos.zip.tmp"
        shutil.copy2(zip_criado, temporario_publicacao)
        temporario_publicacao.replace(pacote_final)

    return pacote_final


if __name__ == "__main__":
    resultado = publicar_relatorio(
        registros=[
            {"id": 101, "total": "199,90"},
            {"id": 102, "total": "49,00"},
        ],
        saida=Path("saida"),
    )
    print(f"Publicado em: {resultado}")
```

O exemplo separa três ciclos de vida:

- os intermediários vivem apenas dentro de `TemporaryDirectory`;
- o `.tmp` de publicação reduz o risco de expor um ZIP pela metade;
- o arquivo final permanece em `saida/`.

Em uma aplicação real, use uma biblioteca apropriada para o PDF, conforme o guia de [relatórios PDF com Python](/blog/python-gerar-pdf-relatorios/). Se a geração depende de LibreOffice, FFmpeg ou outra ferramenta, chame-a com argumentos em lista e timeout, seguindo as práticas de [`subprocess`](/blog/python-subprocess-comandos-externos/).

## Uploads: o que tempfile resolve e o que não resolve

Arquivos enviados por usuários são dados não confiáveis. `tempfile` ajuda a criar um destino sem colisões e sem usar diretamente o nome fornecido pelo navegador, mas não substitui uma política de upload.

Aplique pelo menos estes controles:

1. **limite de tamanho antes e durante a leitura**;
2. **nome gerado pelo servidor**, não pelo usuário;
3. **validação de conteúdo**, não apenas da extensão ou `Content-Type`;
4. **armazenamento fora de diretórios executáveis ou públicos**;
5. **timeout e limite de memória** para conversões;
6. **verificação antimalware**, quando o risco exigir;
7. **remoção garantida** em sucesso e falha;
8. **logs sem conteúdo sensível**.

Não extraia um ZIP recebido diretamente em uma pasta sem validar os caminhos internos. Entradas como `../../arquivo` podem tentar escapar do diretório de destino. O guia de `zipfile` citado anteriormente mostra a proteção contra *path traversal*.

Para dados sensíveis, lembre que apagar um arquivo não garante sobrescrita física em SSDs, sistemas com snapshots ou armazenamento em nuvem. Se o requisito é forte, minimize a gravação, use criptografia e siga a política de retenção da organização.

## Testando com pytest e tmp_path

Se sua função aceita um diretório como argumento, o fixture `tmp_path` do `pytest` costuma ser melhor do que chamar `tempfile` dentro do teste. Ele entrega um `Path` exclusivo e facilita inspeções.

Código da aplicação:

```python
from pathlib import Path


def salvar_resumo(pasta: Path, texto: str) -> Path:
    pasta.mkdir(parents=True, exist_ok=True)
    destino = pasta / "resumo.txt"
    destino.write_text(texto, encoding="utf-8")
    return destino
```

Teste:

```python
from pathlib import Path


def test_salvar_resumo(tmp_path: Path) -> None:
    destino = salvar_resumo(tmp_path / "saida", "concluído")

    assert destino.exists()
    assert destino.read_text(encoding="utf-8") == "concluído"
    assert destino.parent == tmp_path / "saida"
```

Evite afirmar que o caminho começa com `/tmp` ou contém um nome específico. Isso quebra no Windows, em containers configurados de outra forma e até entre versões do Python.

Para testar uma função que usa `TemporaryDirectory` internamente, verifique o resultado que sai da função e, se relevante, que os intermediários não permaneceram. O tutorial de [testes unitários com pytest](/blog/testes-unitarios-python/) cobre fixtures, parametrização e simulação de falhas.

## Boas práticas e erros comuns

Use este checklist em automações e backends:

1. **Prefira `with`.** A limpeza fica ligada ao escopo que usa o recurso.
2. **Use `TemporaryDirectory` para múltiplos artefatos.** É mais simples que gerenciar vários arquivos isolados.
3. **Escolha `NamedTemporaryFile` apenas quando o caminho for necessário.** Caso contrário, `TemporaryFile` reduz exposição.
4. **Chame `flush()` antes de outro leitor abrir o arquivo ainda ativo.** Ou feche-o primeiro para maior portabilidade.
5. **Ao usar `delete=False`, limpe em `finally`.** Uma exceção não pode abandonar o arquivo.
6. **Não confie na extensão.** `.pdf` no nome não transforma bytes arbitrários em PDF válido.
7. **Não use nomes enviados pelo usuário como caminhos.** Preserve o nome original apenas como metadado sanitizado, se necessário.
8. **Defina limites de tamanho e tempo.** Temporários também podem esgotar disco, memória ou inodes.
9. **Não registre conteúdo sensível.** Prefira um identificador interno e métricas de tamanho/duração.
10. **Monitore a pasta temporária em workers de longa duração.** Resíduos indicam encerramento abrupto, `delete=False` sem limpeza ou processos externos travados.
11. **Use `Path` para manipular caminhos.** Ele combina bem com `tempfile` e torna o código mais legível; veja o guia de [`pathlib`](/blog/python-pathlib-manipulacao-caminhos-arquivos/).
12. **Trate erros específicos.** Disco cheio, permissão e arquivo em uso devem aparecer em logs e alertas úteis, como explicado em [tratamento de erros](/blog/tratamento-de-erros-python/) e [logging](/blog/logging-em-python/).

## Qual API escolher?

| Necessidade | API recomendada |
|---|---|
| Vários arquivos de uma única tarefa | `TemporaryDirectory` |
| Outra biblioteca precisa de um caminho | `NamedTemporaryFile` |
| Só seu código usa o objeto de arquivo | `TemporaryFile` |
| Conteúdo pequeno em memória, grande no disco | `SpooledTemporaryFile` |
| Teste que recebe uma pasta | `pytest` com `tmp_path` |
| Controle de baixo nível do descritor | `mkstemp`, com fechamento e limpeza manuais |

Se estiver em dúvida, comece com `TemporaryDirectory`. Uma pasta de trabalho exclusiva deixa claro o que é intermediário, funciona bem com ferramentas externas e simplifica a limpeza de fluxos complexos.

## Perguntas frequentes

### O módulo tempfile precisa ser instalado com pip?

Não. `tempfile` faz parte da biblioteca padrão do Python. Basta importar `TemporaryDirectory`, `NamedTemporaryFile`, `TemporaryFile` ou `SpooledTemporaryFile`. Bibliotecas externas só são necessárias para o restante do fluxo, como gerar PDF, processar imagens ou enviar arquivos a um serviço de nuvem.

### Qual a diferença entre TemporaryFile e NamedTemporaryFile?

`TemporaryFile` cria um arquivo que pode não ter um caminho reutilizável por outro programa, dependendo da plataforma. `NamedTemporaryFile` garante um nome acessível pelo atributo `.name`, sendo a escolha comum quando uma biblioteca ou subprocesso exige um caminho. No Windows, reabrir um arquivo ainda aberto exige atenção às opções de exclusão.

### Quando devo usar TemporaryDirectory?

Use `TemporaryDirectory` quando uma tarefa produz vários arquivos relacionados, como páginas extraídas de um PDF, XMLs descompactados, miniaturas ou artefatos de uma ferramenta externa. O context manager cria uma pasta exclusiva e remove a árvore ao sair do bloco, inclusive quando ocorre uma exceção.

### tempfile torna qualquer upload seguro?

Não. O módulo reduz riscos de nomes previsíveis e colisões, mas o conteúdo recebido ainda precisa de limites de tamanho, validação de tipo e tratamento como dado não confiável. Não execute o arquivo, não use o nome enviado pelo usuário como comando e não confie apenas na extensão.

### Como testar código que cria arquivos temporários?

Para funções que recebem um diretório, use o fixture `tmp_path` do `pytest`, pois ele fornece um `pathlib.Path` isolado por teste. Para testar o uso interno de `tempfile`, valide o resultado observável e a limpeza após o bloco. Não dependa do caminho exato da pasta temporária.

## Conclusão

`tempfile` resolve uma parte invisível, mas importante, do software profissional: criar espaço de trabalho sem colisões e encerrá-lo sem deixar resíduos. A regra prática é combinar `TemporaryDirectory` ou um arquivo temporário com `with`, copiar apenas o resultado que deve sobreviver e manter validação, limites e tratamento de erros ao redor do fluxo.

A API correta depende de quem consumirá o temporário. Se uma ferramenta exige caminho, use `NamedTemporaryFile` ou uma pasta temporária; se apenas seu código precisa de leitura e escrita, `TemporaryFile` é suficiente; se o tamanho varia muito, considere `SpooledTemporaryFile`. Com `pathlib`, testes em `tmp_path`, logs úteis e limpeza em `finally` nos casos manuais, seus scripts ficam mais portáteis e confiáveis — exatamente o tipo de cuidado valorizado em automações, backends e [vagas de Python](/vagas/).
