Python Escrevendo Arquivos
Tudo o que um programa guarda em variáveis some quando ele termina. Para a lista de compras, as vendas do dia ou a tabela de preços da padaria sobreviverem até amanhã, o programa precisa escrever num arquivo. Você já sabe abrir um arquivo com open e with (aula Abrindo Arquivos) e ler o que tem nele (aula Lendo Arquivos). Nesta aula, o caminho contrário: gravar. E o ponto mais importante é um aviso: um dos modos de escrever apaga o que havia, sem perguntar.
- Os três modos de escrita:
"w"(apaga e escreve),"a"(acrescenta no fim) e"x"(só cria arquivo novo). - A escrever com
write, e por que ele não põe a quebra de linha sozinho. - A escrever uma lista de uma vez com
writelines. - A usar o
printque você já conhece para escrever num arquivo:print(..., file=arquivo). - Por que sempre
encoding="utf-8". - Os erros reais:
FileExistsError,TypeError,not writable, a pasta que não existe e o arquivo já fechado.
A ideia: o caderno, a borracha e a página nova
A Ana anota a lista de compras num caderno. Ela tem três jeitos de escrever nele:
| No caderno | Modo | O que acontece com o arquivo |
|---|---|---|
| Apagar a página inteira com a borracha e escrever de novo | "w" (write, "escrever") | Se existe, o conteúdo é apagado. Se não existe, é criado |
| Continuar escrevendo depois da última linha | "a" (append, "acrescentar") | O que havia fica; o novo vai para o fim. Se não existe, é criado |
| Só escrever numa página em branco; se já tiver algo, não mexe | "x" (exclusive, "exclusivo") | Se não existe, é criado. Se já existe, dá erro e nada é tocado |
O modo é o segundo argumento do open. Sem ele, o modo é "r" (read, "ler"), que só lê.
1. Modo "w" e write
O primeiro programa grava a lista de compras da padaria:
with open("compras.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("farinha")
arquivo.write("ovos")
arquivo.write("leite")
- open("compras.txt", "w", encoding="utf-8")
- Abre (ou cria) o arquivo
compras.txtpara escrever, em UTF-8 (a seção 5 explica o porquê). - as arquivo
- O arquivo aberto fica na variável
arquivo. Owithfecha o arquivo sozinho no fim do bloco. - arquivo.write("farinha")
- "Escreva": grava o texto no arquivo, exatamente como está.
O programa roda calado (não tem print). Para ver o que ficou no arquivo, o cat do terminal mostra o conteúdo (o ; echo só pula uma linha no fim, já você vai ver por quê):
$ python3 lista.py $ cat compras.txt; echo farinhaovosleite
Tudo grudado! O write grava só o que você mandou, sem espaço, sem pular linha. Diferente do print, que pula a linha sozinho no fim, o write não acrescenta nada. Quem quer uma linha por item precisa escrever a quebra de linha, o \n (aula Caracteres de Escape):
with open("compras.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("farinha\n")
arquivo.write("ovos\n")
arquivo.write("leite\n")
print("Lista gravada.")
$ python3 lista2.py Lista gravada. $ cat compras.txt farinha ovos leite
Agora sim: uma linha por item. O costume é terminar toda linha com \n, inclusive a última; os programas do terminal (e o próprio Python, ao ler) esperam isso. O cat -A mostra cada final de linha como um $ (aqui, no comquebra.txt da seção 6, que tem as mesmas três linhas):
$ cat -A comquebra.txt farinha$ ovos$ leite$
O write devolve um número
No modo interativo dá para ver um detalhe: o write devolve quantos caracteres escreveu.
$ python3 -q
>>> arquivo = open("teste.txt", "w", encoding="utf-8")
>>> arquivo.write("farinha\n")
8
>>> arquivo.write("pão de queijo\n")
14
>>> arquivo.closed
False
>>> arquivo.close()
>>> arquivo.closed
True
"farinha\n" tem 8 caracteres (o \n conta como um). Num programa em arquivo, esse número aparece só se você der print nele, e quase ninguém usa. Aqui, sem with, o arquivo teve de ser fechado à mão com close() ("fechar"); arquivo.closed diz se ele já está fechado. Com with, você não precisa lembrar disso.
Missão: o programa grava três itens, mas eles saem grudados numa linha só. Acrescente o \n no fim de cada write para o arquivo ficar com 3 linhas. (A segunda parte do programa lê o arquivo de volta e conta as linhas.)
with open("compras.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("farinha")
arquivo.write("ovos")
arquivo.write("leite")
with open("compras.txt", encoding="utf-8") as arquivo:
linhas = arquivo.readlines()
print("Linhas no arquivo:", len(linhas))
print(linhas)
with open("compras.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("farinha\n")
arquivo.write("ovos\n")
arquivo.write("leite\n")
with open("compras.txt", encoding="utf-8") as arquivo:
linhas = arquivo.readlines()
print("Linhas no arquivo:", len(linhas))
print(linhas)
2. Cuidado: o "w" apaga o que havia
O compras.txt tem três itens. A Ana roda outro programa, que grava só o açúcar, também com "w":
with open("compras.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("açúcar\n")
$ python3 apaga.py $ cat compras.txt açúcar
A farinha, os ovos e o leite sumiram. No instante em que o open com "w" abre um arquivo que existe, ele o esvazia, antes mesmo do primeiro write. Não há aviso, não há lixeira, não há "desfazer". Use "w" quando a ideia for mesmo substituir o arquivo inteiro (um relatório refeito do zero, uma tabela de preços nova). Para guardar o que havia, use "a".
3. Modo "a": acrescentar no fim
with open("compras.txt", "a", encoding="utf-8") as arquivo:
arquivo.write("fermento\n")
$ python3 acrescenta.py $ python3 acrescenta.py $ cat compras.txt açúcar fermento fermento
O açúcar ficou, e cada execução acrescentou um fermento no fim. O "a" nunca apaga: é o modo dos históricos, como o registro de vendas do dia ou um arquivo de log (aula logging). Repare no lado ruim: rodou duas vezes, gravou duas vezes. O "a" não confere se a linha já estava lá.
Missão: o vendas.txt (veja a aba) já tem as vendas da manhã. O programa deveria acrescentar a venda nova, mas está apagando as antigas. Troque o modo para que, no fim, o arquivo tenha as três vendas.
with open("vendas.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("bolo de milho,2\n")
with open("vendas.txt", encoding="utf-8") as arquivo:
print(arquivo.read())
pão de queijo,12 bolo de cenoura,3
with open("vendas.txt", "a", encoding="utf-8") as arquivo:
arquivo.write("bolo de milho,2\n")
with open("vendas.txt", encoding="utf-8") as arquivo:
print(arquivo.read())
4. Modo "x": só se ainda não existir
E quando o arquivo não pode ser apagado de jeito nenhum? O relatório de outubro, depois de pronto, não deve ser sobrescrito por engano. O modo "x" cria o arquivo, mas se recusa a abrir um que já existe:
with open("relatorio.txt", "x", encoding="utf-8") as arquivo:
arquivo.write("Relatório de outubro\n")
print("Relatório criado.")
$ python3 novo.py
Relatório criado.
$ python3 novo.py
Traceback (most recent call last):
File "/home/ana/padaria/novo.py", line 1, in <module>
with open("relatorio.txt", "x", encoding="utf-8") as arquivo:
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileExistsError: [Errno 17] File exists: 'relatorio.txt'
- File "/home/ana/padaria/novo.py", line 1
- O erro foi na linha 1, no
open(as marcas~~~~^^^^apontam para ele). - FileExistsError
- "O arquivo já existe".
- [Errno 17] File exists: 'relatorio.txt'
- O código 17 é o que o próprio sistema deu para "já existe", e o nome do arquivo vem no fim.
Na primeira vez, criou. Na segunda, o erro protegeu o relatório: o programa parou antes de escrever, e o arquivo ficou como estava. É um erro bom. Com try e except FileExistsError (aula try e except), o programa pode avisar com calma em vez de mostrar o traceback; é a missão final desta aula.
5. Sempre encoding="utf-8"
Um arquivo de texto guarda bytes, e a codificação (encoding) é a regra que transforma letras em bytes. Para a ou b, quase todas as regras concordam; para ç, ã, é, não. Veja o que acontece quando um arquivo é gravado numa codificação (a cp1252, comum em programas antigos do Windows) e lido em outra:
with open("windows.txt", "w", encoding="cp1252") as arquivo:
arquivo.write("açúcar e café\n")
with open("windows.txt", encoding="utf-8") as arquivo:
print(arquivo.read())
$ python3 latin.py
Traceback (most recent call last):
File "/home/ana/padaria/latin.py", line 4, in <module>
print(arquivo.read())
~~~~~~~~~~~~^^
File "<frozen codecs>", line 325, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe7 in position 1: invalid continuation byte
"O decodificador UTF-8 não consegue ler o byte 0xe7 na posição 1". A posição 1 é o ç de "açúcar": na cp1252, ele virou um byte (0xe7) que não faz sentido em UTF-8. Escrever e ler com a mesma codificação resolve, e a UTF-8 é a que funciona em todo lugar: Linux, macOS, Windows, navegadores. Por isso o guia escreve encoding="utf-8" em todo open.
encoding?
Sem ele, o Python usa a codificação padrão do sistema. No Ubuntu da Ana, é UTF-8, e tudo funciona; no Windows, até o Python 3.14, costuma ser outra, e o mesmo programa grava acentos diferentes. A partir do Python 3.15, o padrão passa a ser UTF-8 em todo lugar (PEP 686). Escrever encoding="utf-8" deixa o programa certo em qualquer versão e em qualquer computador.
6. Uma lista de uma vez: writelines
writelines ("escrever linhas") grava todos os textos de uma lista, um depois do outro. O nome engana:
itens = ["farinha", "ovos", "leite"]
with open("semquebra.txt", "w", encoding="utf-8") as arquivo:
arquivo.writelines(itens)
with open("comquebra.txt", "w", encoding="utf-8") as arquivo:
arquivo.writelines(item + "\n" for item in itens)
$ python3 linhas.py $ cat semquebra.txt; echo farinhaovosleite $ cat comquebra.txt farinha ovos leite
- arquivo.writelines(itens)
- Grava os três textos grudados: apesar do nome, o
writelinestambém não põe\n. É o mesmo que umwritepara cada item. - item + "\n" for item in itens
- Monta cada item já com a quebra de linha, como numa list comprehension sem os colchetes (aula List Comprehension).
Outra forma, bem comum, é juntar tudo num texto só antes: arquivo.write("\n".join(itens) + "\n") (o join está na aula Métodos de Texto).
7. print(..., file=arquivo): o print que você já conhece
O print sabe escrever num arquivo: basta dizer file=. E ele faz tudo o que faz na tela: pula a linha no fim, separa os valores com espaço, converte números em texto.
precos = {"bolo de cenoura": 35.0, "pão de queijo": 2.5, "café": 4.0}
with open("precos.txt", "w", encoding="utf-8") as arquivo:
print("Tabela de preços", file=arquivo)
for produto, preco in precos.items():
print(f"{produto}: R$ {preco:.2f}", file=arquivo)
print("Tabela gravada.")
$ python3 com_print.py Tabela gravada. $ cat precos.txt Tabela de preços bolo de cenoura: R$ 35.00 pão de queijo: R$ 2.50 café: R$ 4.00
Só o último print, sem file=, apareceu na tela; os outros foram para o arquivo, cada um na sua linha, sem nenhum \n escrito à mão. O :.2f deixa duas casas decimais (aula f-strings).
Missão: o recibo está saindo na tela. Faça cada linha ir para o arquivo recibo.txt: acrescente file=arquivo nos três print de dentro do with. (O programa mostra o arquivo no fim.)
pedido = {"bolo de cenoura": 2, "pão de queijo": 1}
precos = {"bolo de cenoura": 35.0, "pão de queijo": 2.5}
with open("recibo.txt", "w", encoding="utf-8") as arquivo:
total = 0
for produto, quantidade in pedido.items():
subtotal = quantidade * precos[produto]
total += subtotal
print(f"{quantidade} x {produto}: R$ {subtotal:.2f}")
print("-" * 20)
print(f"Total: R$ {total:.2f}")
with open("recibo.txt", encoding="utf-8") as arquivo:
print("No recibo.txt:")
print(arquivo.read())
pedido = {"bolo de cenoura": 2, "pão de queijo": 1}
precos = {"bolo de cenoura": 35.0, "pão de queijo": 2.5}
with open("recibo.txt", "w", encoding="utf-8") as arquivo:
total = 0
for produto, quantidade in pedido.items():
subtotal = quantidade * precos[produto]
total += subtotal
print(f"{quantidade} x {produto}: R$ {subtotal:.2f}", file=arquivo)
print("-" * 20, file=arquivo)
print(f"Total: R$ {total:.2f}", file=arquivo)
with open("recibo.txt", encoding="utf-8") as arquivo:
print("No recibo.txt:")
print(arquivo.read())
Formas diferentes de escrever
| Jeito | Exemplo | Quando usar |
|---|---|---|
write | arquivo.write("ovos\n") | Você controla cada caractere. Lembre do \n |
writelines | arquivo.writelines(linhas) | Os textos já estão numa lista, cada um já com o seu \n |
write + join | arquivo.write("\n".join(itens) + "\n") | Uma lista de textos sem \n, numa linha de código |
print(file=) | print(produto, preco, file=arquivo) | Relatórios e recibos: pula linha, separa com espaço e aceita números |
| Módulos próprios | csv, json | Planilhas e dados estruturados (aulas CSV e JSON) |
| Modo | Arquivo não existe | Arquivo existe | Use para |
|---|---|---|---|
"w" | Cria | Apaga e escreve do zero | Refazer o arquivo inteiro |
"a" | Cria | Acrescenta no fim | Históricos, registros, logs |
"x" | Cria | FileExistsError, não mexe | Nunca sobrescrever por engano |
"r" (padrão) | FileNotFoundError | Só lê | Ler (aula Lendo Arquivos) |
Quando dá errado
TypeError
total = 42
with open("total.txt", "w", encoding="utf-8") as arquivo:
arquivo.write(total)
$ python3 numero.py
Traceback (most recent call last):
File "/home/ana/padaria/numero.py", line 3, in <module>
arquivo.write(total)
~~~~~~~~~~~~~^^^^^^^
TypeError: write() argument must be str, not int
"O argumento do write() tem de ser str (texto), não int (número inteiro)". O print converte sozinho; o write, não. Como consertar: converta antes, com arquivo.write(str(total) + "\n") ou arquivo.write(f"{total}\n"), ou use print(total, file=arquivo).
not writable
with open("compras.txt", encoding="utf-8") as arquivo:
arquivo.write("manteiga\n")
$ python3 leitura.py
Traceback (most recent call last):
File "/home/ana/padaria/leitura.py", line 2, in <module>
arquivo.write("manteiga\n")
~~~~~~~~~~~~~^^^^^^^^^^^^^^
io.UnsupportedOperation: not writable
"Operação não suportada: não dá para escrever". Faltou o modo no open, e sem ele o arquivo abre só para leitura ("r"). io é o módulo do Python que cuida de arquivos, por isso o nome completo do erro é io.UnsupportedOperation. Como consertar: open("compras.txt", "a", encoding="utf-8") (ou "w", se a ideia for substituir).
FileNotFoundError ao escrever
with open("relatorios/outubro.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("Vendas de outubro\n")
$ python3 pasta.py
Traceback (most recent call last):
File "/home/ana/padaria/pasta.py", line 1, in <module>
with open("relatorios/outubro.txt", "w", encoding="utf-8") as arquivo:
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'relatorios/outubro.txt'
Estranho: "arquivo não encontrado", ao criar um arquivo? O "w" cria o arquivo, mas não cria pastas, e a pasta relatorios não existe. Como consertar: crie a pasta antes, com os.makedirs("relatorios", exist_ok=True) (aula os e sys) ou com o pathlib (aula Pastas e Caminhos).
$ python3 modo.py
Traceback (most recent call last):
File "/home/ana/padaria/modo.py", line 1, in <module>
with open("compras.txt", "escrever", encoding="utf-8") as arquivo:
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: invalid mode: 'escrever'
"Modo inválido". O modo é uma letra, em inglês: "w", "a", "x" ou "r".
Continuando a sessão do >>> da seção 1, depois do close():
>>> arquivo.write("ovos\n")
Traceback (most recent call last):
File "<python-input-6>", line 1, in <module>
arquivo.write("ovos\n")
~~~~~~~~~~~~~^^^^^^^^^^
ValueError: I/O operation on closed file.
"Operação de entrada/saída num arquivo fechado". Com with, acontece o mesmo se o write ficar fora do bloco (sem os 4 espaços): o arquivo já foi fechado quando o bloco terminou. Como consertar: deixe todos os write indentados dentro do with.
"w" que apagou o que não devia
Não tem traceback, e por isso é o mais perigoso: você viu na seção 2. Se o arquivo guarda algo que não pode se perder, abra com "a" (para acrescentar) ou com "x" (para só criar). E guarde cópias dos arquivos importantes.
Referência rápida
| Código | O que faz |
|---|---|
with open("x.txt", "w", encoding="utf-8") as arquivo: | Abre para escrever, apagando o que havia (cria se não existir) |
open("x.txt", "a", encoding="utf-8") | Abre para acrescentar no fim |
open("x.txt", "x", encoding="utf-8") | Cria; FileExistsError se já existir |
arquivo.write("texto\n") | Escreve o texto, sem acrescentar nada (devolve quantos caracteres) |
arquivo.writelines(lista) | Escreve cada texto da lista, grudados |
print(..., file=arquivo) | Escreve como o print: com espaço entre os valores e \n no fim |
arquivo.close() / arquivo.closed | Fecha o arquivo / diz se está fechado (com with, é automático) |
| Mensagem | Causa provável |
|---|---|
FileExistsError: [Errno 17] File exists | Modo "x" e o arquivo já existe |
TypeError: write() argument must be str, not int | write de um número: converta com str() ou f-string |
io.UnsupportedOperation: not writable | Faltou o modo "w"/"a"/"x" no open |
FileNotFoundError ao escrever | A pasta do caminho não existe |
ValueError: invalid mode | Modo escrito errado |
ValueError: I/O operation on closed file. | write depois do close() ou fora do bloco with |
UnicodeDecodeError: 'utf-8' codec can't decode… | Gravado numa codificação, lido em outra: use UTF-8 nos dois |
| Tudo numa linha só, sem erro | Faltou o \n no write/writelines |
Exercícios
1. Acrescentar sem apagar
Complete o modo que acrescenta no fim do arquivo:
2. A quebra de linha
Complete para gravar "ovos" numa linha própria:
3. O print no arquivo
Complete o argumento que manda o print para o arquivo:
4. O compras.txt tem 10 itens. O que sobra depois de open("compras.txt", "w", encoding="utf-8") com um write("sal\n")?
5. arquivo.writelines(["farinha", "ovos"]) grava o quê?
6. Qual modo protege um arquivo que já existe de ser sobrescrito?
Missão final: não apague o relatório antigo
Missão: o relatorio.txt (veja a aba) já existe, e o programa está apagando o conteúdo dele. Abra com o modo "x" e, num try/except FileExistsError:, mostre O relatório já existe; nada foi apagado. No fim, o arquivo deve continuar com o texto antigo.
with open("relatorio.txt", "w", encoding="utf-8") as arquivo:
arquivo.write("Relatório novo\n")
print("Relatório gravado.")
with open("relatorio.txt", encoding="utf-8") as arquivo:
print("Conteúdo:", arquivo.read())
Relatório antigo: vendas de setembro
try:
with open("relatorio.txt", "x", encoding="utf-8") as arquivo:
arquivo.write("Relatório novo\n")
print("Relatório gravado.")
except FileExistsError:
print("O relatório já existe; nada foi apagado.")
with open("relatorio.txt", encoding="utf-8") as arquivo:
print("Conteúdo:", arquivo.read())
Resumo
- Para escrever, o
openrecebe um modo:"w"apaga e escreve,"a"acrescenta no fim,"x"só cria arquivo novo (senão,FileExistsError). - O
"w"esvazia o arquivo no momento doopen, sem aviso. writeewritelinesgravam o texto exatamente como está: a quebra de linha\né por sua conta. E só aceitam texto (str).print(..., file=arquivo)escreve como na tela: separa com espaço, converte números e pula a linha.- Sempre
encoding="utf-8", e semprewith, que fecha o arquivo sozinho. - O
"w"cria arquivos, mas não pastas: crie a pasta antes.