Módulo 16 - Projeto final: seu gerenciador de tarefas

Salvando e carregando do arquivo

12 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

O que você vai aprender

  • Desenhar o formato do arquivo: uma tarefa por linha, status;texto.
  • Implementar salvar_tarefas com with open no modo w e encoding utf-8.
  • Implementar carregar_tarefas com try/except FileNotFoundError e split para reconstruir os dicionários.
  • Ligar tudo no loop: salvar após cada mudança e carregar na abertura do programa.

O formato do arquivo: simples de gravar, simples de ler

Antes de gravar qualquer coisa, precisamos combinar um formato: como uma tarefa, que dentro do programa é um dicionário, vira uma linha de texto dentro do arquivo? A resposta escolhida é a mais simples que funciona: cada linha carrega o status e o texto, separados por ponto e vírgula. O status é um caractere só, 0 para pendente e 1 para concluída. Um arquivo com duas tarefas fica assim:

0;Comprar pão
1;Pagar conta de luz

O conteúdo do tarefas.txt: Comprar pão está pendente (0) e Pagar conta de luz está concluída (1).

Por que o status vem antes do texto, e não depois? Porque o status tem tamanho fixo (um caractere) e o texto tem tamanho livre. Com o campo fixo na frente, o split(";", 1) corta a linha na primeira ocorrência do separador e pronto: tudo que vier depois, inclusive outros pontos e vírgulas que o usuário tenha digitado na tarefa, permanece intacto no texto. Se o texto viesse primeiro, um ponto e vírgula digitado no meio da tarefa embaralharia a leitura. Formato de arquivo é decisão de projeto, e essa ordem esperta evita uma classe inteira de defeitos.

Outra decisão: a estratégia de gravação. Em vez de tentar editar linhas específicas do arquivo, o salvar_tarefas reescreve o arquivo do zero a cada chamada, com o modo w do módulo 15. Para uma lista pessoal de tarefas, reescrever tudo custa menos de um piscar de olhos e simplifica o código de forma brutal: uma única função de gravação serve para adicionar, concluir e remover.

Implementando salvar_tarefas e carregar_tarefas

Duas mudanças no gerenciador.py. Primeiro, logo no topo do arquivo, antes das funções, crie a constante com o nome do arquivo, para ele morar num lugar só. Depois, substitua o pass de salvar_tarefas e o return [] de carregar_tarefas pelas versões de verdade:

ARQUIVO = "tarefas.txt"

def salvar_tarefas(tarefas):
    with open(ARQUIVO, "w", encoding="utf-8") as arquivo:
        for tarefa in tarefas:
            if tarefa["concluida"]:
                status = "1"
            else:
                status = "0"
            arquivo.write(status + ";" + tarefa["texto"] + "\n")

salvar_tarefas: abre no modo w (reescreve), percorre a lista e grava status;texto com quebra de linha no final de cada tarefa.

O with garante o fechamento do arquivo mesmo se algo der errado no meio, como o módulo 15 ensinou, e o encoding utf-8 garante que Almoçar com a vovó seja gravado e lido com os acentos no lugar, em qualquer sistema. O if traduz o True/False do dicionário para o 1/0 do arquivo, e o \n no final de cada write é o que separa as tarefas em linhas. Agora o caminho de volta, que é a leitura na abertura:

def carregar_tarefas():
    tarefas = []
    try:
        with open(ARQUIVO, "r", encoding="utf-8") as arquivo:
            for linha in arquivo:
                linha = linha.strip()
                if linha == "":
                    continue
                status, texto = linha.split(";", 1)
                tarefas.append({"texto": texto, "concluida": status == "1"})
    except FileNotFoundError:
        pass
    return tarefas

carregar_tarefas: lê linha a linha, limpa a quebra com strip, pula linhas vazias e reconstrói cada dicionário com split.

Dois pontos finos merecem lupa. O primeiro é o status == "1" dentro do append: essa comparação já resulta em True ou False, então ela reconstrói o campo concluida direto, sem precisar de if. É a tradução inversa da gravação: o 1/0 do arquivo virando o True/False do dicionário. O segundo é o except FileNotFoundError com pass: na primeira vez que alguém roda o programa, o tarefas.txt ainda não existe, e o open no modo r levantaria erro. O except captura essa situação específica e deixa a função seguir para o return tarefas, devolvendo a lista vazia criada no começo. Primeira execução sem arquivo não é erro, é só um usuário novo.

Ligando tudo no loop principal

As funções existem, mas ninguém as chama ainda. Faltam as duas costuras no programa principal: carregar na abertura e salvar após cada mudança. A primeira é trocar a linha tarefas = [] por tarefas = carregar_tarefas(). A segunda é chamar salvar_tarefas logo depois de cada ação que altera a lista, ou seja, nas opções 1, 3 e 4. A opção 2 só lê, então não precisa gravar nada. O programa principal fica assim:

tarefas = carregar_tarefas()

while True:
    mostrar_menu()
    opcao = input("Escolha uma opção: ")
    if opcao == "1":
        adicionar_tarefa(tarefas)
        salvar_tarefas(tarefas)
    elif opcao == "2":
        listar_tarefas(tarefas)
    elif opcao == "3":
        concluir_tarefa(tarefas)
        salvar_tarefas(tarefas)
    elif opcao == "4":
        remover_tarefa(tarefas)
        salvar_tarefas(tarefas)
    elif opcao == "5":
        print("Até logo!")
        break
    else:
        print("Opção inválida. Digite um número de 1 a 5.")

O loop com as costuras: carregar_tarefas na abertura e salvar_tarefas após adicionar, concluir e remover.

Por que salvar após cada mudança, em vez de uma vez só na saída? Porque a vida real derruba programas: acabou a luz, fechou o terminal sem querer, o computador reiniciou. Salvando a cada alteração, o pior cenário perde só a digitação em andamento, nunca a lista. É o mesmo princípio do salvamento automático dos editores de texto modernos, e custa uma linha por opção.

Agora o teste que muda tudo: adicione duas tarefas, conclua uma, saia com a opção 5 e RODE O PROGRAMA DE NOVO. Escolha listar. As tarefas estão lá, com o status certinho. Se estiver rodando no seu computador, abra o tarefas.txt na pasta do projeto e veja as linhas 0;texto e 1;texto com os próprios olhos. Esse momento, em que o seu programa lembra do passado, é a fronteira entre script de estudo e ferramenta de verdade.

Teste rápido

Na primeira execução do programa, o arquivo tarefas.txt ainda não existe. O que acontece?

Perguntas frequentes

Por que gravar 0 e 1 no arquivo em vez de escrever False e True?
Os dois funcionariam, mas 0 e 1 são mais curtos, imunes a variações de escrita (true, TRUE, True) e a reconstrução vira uma comparação única: status == "1". Lembre que tudo num arquivo de texto é string; gravar True salvaria a palavra, não o valor booleano, e a leitura teria que interpretar do mesmo jeito.
O modo w não apaga o arquivo inteiro? Não é perigoso?
Apaga e reescreve, e nesse desenho isso é a segurança, não o perigo: o arquivo sempre espelha a lista completa que está na memória, sem estados pela metade. O risco existiria se gravássemos só parte dos dados; como salvar_tarefas percorre a lista inteira a cada chamada, o espelho é fiel.
E se o usuário digitar um ponto e vírgula dentro do texto da tarefa?
Nada quebra, e o mérito é do split(";", 1): o limite 1 faz um corte só, na primeira ocorrência, que é a do separador oficial entre status e texto. Uma tarefa como Comprar arroz; feijão volta inteira do arquivo, com o ponto e vírgula preservado no texto.
Por que salvar depois de cada mudança em vez de salvar só ao sair?
Porque a saída limpa pela opção 5 é o cenário otimista. Queda de luz, terminal fechado no x e travamento do sistema acontecem, e salvar só na saída perderia a sessão inteira. Gravando após cada alteração, o arquivo está sempre no máximo uma digitação atrás da memória.
Onde o arquivo tarefas.txt é criado no meu computador?
Na pasta a partir da qual você executou o programa, porque o nome no open não tem caminho, só o arquivo. Rodando pelo VS Code na pasta do projeto, ele aparece ao lado do gerenciador.py. Se o programa parece não lembrar das tarefas, confira se você não o executou a partir de outra pasta.
Por que não usar um banco de dados em vez de um arquivo de texto?
Porque a ferramenta deve caber no problema. Uma lista pessoal com dezenas de tarefas vive muito bem num arquivo de texto legível a olho nu, que ainda ajuda no estudo: você abre e confere o formato. Bancos de dados entram quando há muitos dados, muitos acessos simultâneos ou buscas complexas, e são assunto para depois desta trilha.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.