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.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: Salvando e carregando do arquivo.
Os objetivos desta aula. 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.
Veja o essencial, parte por parte.
O formato do arquivo: simples de gravar, simples de ler. O tarefas.txt guarda uma tarefa por linha, no formato status;texto, onde 0 é pendente e 1 é concluída.
Implementando salvar_tarefas e carregar_tarefas. Esquecer o encoding="utf-8" nos DOIS open: no Windows, acentos gravados com um encoding e lidos com outro viram caracteres embaralhados.
Ligando tudo no loop principal. As funções existem, mas ninguém as chama ainda.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
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 luzO 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 tarefascarregar_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.