Como Manipular Arquivos em Python do Jeito Mais Eficiente

Quando um programa é finalizado, as variáveis na memória do computador são perdidas.

Por isso, para guardar dados entre as execuções de um programa, é preciso usar arquivos.

Para realizar essa tarefa, todas as linguagens de programação têm mecanismos que permitem interagir com o sistema operacional para ler e escrever arquivos.

Em uma linguagem de alto nível como Python, até essas operações de baixo nível são representadas como abstrações realizadas por objetos.

Isso significa que há várias maneiras de realizar uma mesma operação, mas nem todas elas são eficientes ou seguras, ainda mais quando o arquivo é muito grande.

Para que você não perca tempo procurando a melhor maneira de manipular um arquivo em Python, nesse post eu te mostro como fazer isso do jeito mais eficiente.

Antes de aprender como manipular os arquivos e seu conteúdo, é importante que você entenda a diferença entre dois tipos de arquivos: Texto e Binário.

Qual é a Diferença entre Arquivo Texto e Binário?

Quando você abre um arquivo para manipular seu conteúdo em um programa, esse arquivo pode ser de dois tipos:

  1. Texto, que só contém caracteres. Esses caracteres são representados em algum esquema de codificação, como ASCII ou UTF-8.
  2. Binário, que tem dados organizados em um formato específico, definido pelo algoritmo que cria esse tipo de arquivo.

Arquivos com extensão txt, csv e json são exemplos de arquivos texto.

Alguns exemplos de arquivos binários são imagens jpeg, png, e gif, além de formatos proprietários de softwares comerciais, como xls, para o Microsoft Excel e pdf.

Pode ser que você esteja pensando:

Como eu vou saber se o meu programa deve abrir o arquivo como texto ou como binário?

Essa é uma dúvida comum, mas a resposta é simples.

O seu programa atende a um caso de uso específico, então você sabe o que esperar quando escreve o código para processar um arquivo.

Na verdade, isso pode ser resumido da seguinte maneira:

Um arquivo é como qualquer outra entrada do sistema, como um valor informado pelo usuário.

Por exemplo, quando o seu programa pergunta a altura do usuário, esse valor é guardado em uma variável do tipo float, que vai ser usada em algum cálculo.

Se o usuário digita “amarelo” para informar a altura, o programa identifica que essa não é uma entrada válida e lança um erro.

O mesmo acontece para os tipos de arquivos.

Imagine que o seu programa espera receber um arquivo csv, onde cada linha tem um número de matrícula, um nome de aluno e as notas do aluno por disciplina.

Um arquivo csv é só um arquivo texto com os valores separados por vírgulas.

Se esse programa receber um arquivo jpeg, que é um arquivo binário, ele vai processar essa entrada como se fosse um arquivo csv no formato esperado.

É claro que o resultado é um erro.

Erro GIMP arquivo inválido
Figura 1 – Editor de imagens GIMP informando erro ao tentar abrir um arquivo de sistema.

No entanto, o seu programa pode ser capaz de processar um conjunto de arquivos com características semelhantes, mas com formatos diferentes. Por exemplo, alguns formatos de imagens, como jpeg, png e webp.

Nesse caso, é necessário identificar o tipo correto de arquivo binário antes de processar o seu conteúdo.

Há duas maneiras simples de determinar o tipo de um arquivo:

  1. Avaliando a sua extensão. Por exemplo, .webp, .jpg ou .png.
  2. Lendo o conteúdo e identificando o “número mágico” no início do arquivo, antes dos dados.

O problema de usar apenas a extensão é que ela pode ser alterada por qualquer usuário que tenha acesso ao arquivo no sistema operacional.

Por isso, é fundamental sempre verificar o número mágico e o conteúdo do arquivo antes de realizar qualquer processamento sobre ele.

Essa regra também vale para os arquivos de texto.

Se você tentar processar um arquivo html como se fosse um arquivo csv, o resultado vai ser um erro.

No entanto, para os arquivos texto, o número mágico não faz sentido, a não ser que a codificação desses arquivos seja UTF-8 ou UTF-16.

Nesse caso, a solução é ler o texto do arquivo e identificar se o formato está de acordo com o que foi especificado.

Agora que você já sabe qual é a diferença entre os arquivos de texto e binários, veja como abrir, fechar e manipular o conteúdo desses arquivos.

Eu sugiro que você execute o código Python mostrado nesse post no Jupyter Lab para treinar.

O Jupyter Lab é uma ferramenta ótima para começar a programar e deve fazer parte da sua lista de ferramentas como programador.

Se você ainda não tem o Jupyter Lab instalado, dá uma olhada nesse post onde eu explico o passo-a-passo para a instalação.

Como Abrir e Fechar um Arquivo em Python

Para abrir um arquivo em Python use a função embutida open(), informando o caminho do arquivo no sistema operacional e o modo de abertura.

ModoResultado
'r'Abre o arquivo para leitura. Esse é o padrão, caso o modo não seja especificado.
'w'Abre o arquivo para escrita e trunca o seu conteúdo. Nesse modo, tudo o que estiver escrito no arquivo é perdido. Se o arquivo não existir, ele é criado.
'x'Cria um arquivo novo, aberto para escrita no “modo de criação exclusiva”. Esse modo significa que o arquivo não pode existir antes de ser aberto. Se o arquivo já existir, um erro é gerado.
'a'Abre o arquivo para escrita sem truncar seu conteúdo. Os dados são escritos no final do arquivo. Se o arquivo não existir, ele é criado.
'b'Usado em conjunto com os modos anteriores para abrir um arquivo binário. Por exemplo, 'rb' abre um arquivo em modo binário para leitura e 'wb' abre um arquivo em modo binário para escrita.
't'Abre o arquivo em modo texto. Esse é o padrão, então o uso desse modo é opcional. Por exemplo, o modo 'r' funciona de mesma maneira que o modo 'rt'.
'+'Abre o arquivo para leitura e escrita. Nesse caso, o arquivo não é truncado. Exemplo: 'r+' A escrita sempre acontece no fim do arquivo.
Tabela 1 – Modos de abertura de arquivos com o método open() em Python.

Além do modo de abertura, a codificação de um arquivo texto também pode ser informada ao método open(), usando o parâmetro encoding.

Exemplos de uso do método open() para abrir arquivos:

#  Abre um arquivo texto para leitura
arq = open('arquivo.txt', 'r', encoding = 'utf-8')

#  Abre um arquivo binário de imagem para leitura e escrita
arq = open('foto.jpg', 'r+b')Code language: Python (python)

A função open() abre o arquivo e retorna um objeto que deve ser atribuído a uma variável, para que o conteúdo do arquivo possa ser manipulado.

Esse objeto é um manipulador de arquivo (file handler). Todos os métodos que afetam o conteúdo do arquivo são chamados a partir desse objeto.

Se você quiser usar arquivos de maneira eficiente nos seus programas, é importante entender que os sistemas operacionais possuem um limite máximo de arquivos que podem ser abertos.

Por isso, após abrir um arquivo e processar o seu conteúdo, é preciso usar o método close() para fechar o arquivo, evitando desperdício de recursos.

arq.close()Code language: Python (python)

É claro que se você tentar fazer qualquer operação sobre o arquivo depois que ele for fechado, o resultado é um ValueError.

Para facilitar, existe uma opção para você não precisar fechar o arquivo de forma explícita, usando a sintaxe mostrada a seguir para abrir o arquivo.

with open('arquivo.txt', 'r') as arq:
    #  Operações com o arquivo

#  O arquivo é fechado no fim do bloco de código with.Code language: Python (python)

O bloco with <função> as <variável>: é chamado de Gerenciador de Contexto (context manager) e o seu uso é considerado uma boa prática de programação em Python.

Escrevendo o código dessa forma, o gerenciador de contexto fica responsável por liberar os recursos de volta para o sistema operacional quando o bloco with termina, sem que você precise chamar o método close().

Uma vez aberto o arquivo, você pode ler e escrever dados usando os métodos do manipulador de arquivo retornado pela função open().

Veja como manipular o conteúdo do arquivo nas seções a seguir.

Como Ler um Arquivo em Python

Para ler o conteúdo de um arquivo em Python, abra o arquivo e use os métodos read(), readline() e readlines().

O método read() lê todo o conteúdo do arquivo para a memória de uma vez só.

Isso pode ser um problema, se o arquivo for muito grande.

Imagine que você está trabalhando com um arquivo que tem o conteúdo abaixo.

Matricula   Nome  Nota1 Nota2 Nota3 Nota4
20201201923 Maria 5.5   6.5   8.5   7.0
20201299384 João  9.0   9.5   6.5   7.0Code language: plaintext (plaintext)

Veja um exemplo de como ler todo o conteúdo desse arquivo usando o método read().

>>> with open('arquivo.txt', 'r', encoding = 'utf-8') as arq:
...     texto = arq.read()
...     print(texto)
...
Matricula   Nome  Nota1 Nota2 Nota3 Nota4
20201201923 Maria 5.5   6.5   8.5   7.0
20201299384 João  9.0   9.5   6.5   7.0Code language: Python (python)

O conteúdo do arquivo é retornado pelo método read() em um objeto do tipo str se ele estiver aberto no modo texto, ou como um objeto bytes, se ele estiver aberto no modo binário.

Para reduzir o uso de memória, no caso de um arquivo muito grande, é possível informar ao método read() o tamanho do texto ou a quantidade de bytes que você quer ler do arquivo.

No exemplo abaixo, apenas a primeira linha do arquivo é impressa, ou seja, os primeiros 41 caracteres.

>>> with open('arquivo.txt', 'r', encoding = 'utf-8') as arq:
...     texto = arq.read(41)
...     print(texto)
...
Matricula   Nome  Nota1 Nota2 Nota3 Nota4Code language: Python (python)

De forma diferente, o método readline() lê apenas uma linha do arquivo e retorna o conteúdo como uma string, mantendo o caractere de nova linha \n no fim da string.

Com o método readline(), é possível ler uma linha específica de um arquivo texto usando Python.

O código do exemplo a seguir lê apenas a primeira e a segunda linha do arquivo.

>>> with open('arquivo.txt', 'r', encoding = 'utf-8') as arq:
...     texto = arq.readline()
...     print(texto)
...     texto = arq.readline()
...     print(texto)
...
Matricula   Nome  Nota1 Nota2 Nota3 Nota4

20201201923 Maria 5.5   6.5   8.5   7.0Code language: Python (python)

o método readlines() lê todo o arquivo e retorna uma lista, onde cada linha é um elemento.

Esse método é muito útil, já que o conteúdo do arquivo pode ser manipulado como uma lista.

No entanto, assim como no método read(), essa operação coloca todo o conteúdo do arquivo na memória de uma vez e é inviável se o arquivo for muito grande.

>>> with open('arquivo.txt', 'r', encoding = 'utf-8') as arq:
...     arq.readlines()
...
['Matricula   Nome  Nota1 Nota2 Nota3 Nota4\n',
 '20201201923 Maria 5.5   6.5   8.5   7.0\n',
 '20201299384 João  9.0   9.5   6.5   7.0']Code language: Python (python)

O mesmo resultado pode ser obtido usando a função embutida list() e passando o manipulador de arquivo como argumento.

>>> with open('arquivo.txt', 'r', encoding = 'utf-8') as arq:
...     list(arq)
...
['Matricula   Nome  Nota1 Nota2 Nota3 Nota4\n',
 '20201201923 Maria 5.5   6.5   8.5   7.0\n', 
 '20201299384 João  9.0   9.5   6.5   7.0']Code language: Python (python)

Os arquivos binários não têm o conceito de linhas e todo o seu conteúdo é visto como uma coleção de bytes.

Por isso, os métodos readline() e readlines() não fazem sentido para esse tipo de arquivo.

Como Ler um Arquivo Linha a Linha em Python

A maneira mais eficiente de ler um arquivo linha a linha em Python é usando um laço for para iterar sobre o manipulador do arquivo (file handler). Nesse caso, o resultado é o mesmo de chamar o método readline() para cada linha do arquivo.

>>> with open('arquivo.txt', 'r', encoding = 'utf-8') as arq:
...     for texto in arq:
...         print(texto)
...
Matricula   Nome  Nota1 Nota2 Nota3 Nota4

20201201923 Maria 5.5   6.5   8.5   7.0

20201299384 João  9.0   9.5   6.5   7.0Code language: JavaScript (javascript)

Como Criar um Arquivo Texto em Python

Para que o seu programa possa ler um arquivo, você precisa usar um arquivo existente ou gravar dados em um novo arquivo.

A maneira de escrever em um arquivo em Python é usando o método write(<dados>).

Para conseguir usar o método write(), é preciso que o arquivo esteja aberto em um dos modos de escrita.

Nesse caso, você tem três opções, dependendo do que você quer fazer com o arquivo:

  1. Não importa se o arquivo já existe ou não, ou então ele existe, mas o seu conteúdo pode ser apagado. Nesse caso, use o modo ‘w‘.
  2. O arquivo já existe e você não quer perder o conteúdo dele. Use o modo ‘a‘ e adicione novos dados ao fim do arquivo.
  3. Você não quer adicionar dados a um arquivo existente e nem perder o conteúdo desse arquivo. Nesse caso, use o modo ‘x‘ para ter certeza de que um novo arquivo será criado do zero.

Além dessas opções, use o modificador '+' se também quiser ler a partir do arquivo em modo de escrita.

Usando o exemplo da seção anterior, se você quiser adicionar uma linha ao arquivo de notas, use o código abaixo.

with open('arquivo.txt', 'a', encoding = 'utf-8') as arq:
    arq.write('\n20201299385 Carol 10.0  9.5   9.5   10.0')Code language: Python (python)

Como boa prática, eu sugiro que você use um objeto ou pelo menos uma estrutura de dados simples que represente a linha do arquivo.

Como Salvar um Lista ou um Array em um Arquivo Texto em Python

Se a linha do exemplo anterior fosse escrita como uma lista, bastaria salvar essa lista no arquivo texto. O código ficaria assim:

linha = ['\n20201299385 ', 'Carol ', '10.0  ', '9.5   ', '9.5   ', 10.0]
with open('arquivo.txt', 'a', encoding = 'utf-8') as arq:
    for valor in linha:
        valor = str(valor)
        arq.write(valor)Code language: Python (python)

O exemplo acima usa um laço for para iterar sobre os elementos da lista. Isso é só para demonstrar que todos os elementos da lista têm que ser do tipo str, senão o método write() gera um TypeError.

Se você já leu o meu post com 13 Dicas Úteis para Manipular Strings em Python do Jeito Mais Fácil, você sabe que a maneira mais eficiente de transformar uma lista em string é usando o método join().

O código acima ficaria ainda mais simples usando esse método. Observe que o método join() também exige que todos os elementos da lista sejam do tipo str.

linha = ['\n20201299385 ', 'Carol ', '10.0  ', '9.5   ', '9.5   ', '10.0  ']
with open('arquivo.txt', 'a', encoding = 'utf-8') as arq:
    arq.write(''.join(linha))Code language: Python (python)

O exemplo acima funcionaria do mesmo jeito se a linha fosse escrita como um array.

import numpy as np
linha = np.array(['\n20201299385 ', 'Carol ', '10.0  ', '9.5   ', '9.5   ', 10.0])
with open('arquivo.txt', 'a', encoding = 'utf-8') as arq:
    for valor in linha:
        arq.write(valor)Code language: Python (python)

Esses exemplos mostram como salvar uma lista ou um array em um arquivo texto em Python.

Na verdade, qualquer sequência pode ser usada para salvar dados em um arquivo usando essa mesma lógica.

Agora que você já sabe como ler e gravar dados, veja o jeito mais eficiente de fazer edições mais complexas em um arquivo no Python.

Como Apagar uma Linha de um Arquivo Texto em Python

Para apagar uma linha de um arquivo texto em Python, abra o arquivo em modo de leitura e copie todas as linhas, menos a linha que deve ser apagada, para um arquivo temporário, aberto em modo de escrita. Quando terminar a cópia, substitua o arquivo original pelo temporário.

Se o arquivo original for grande demais e não couber na memória do computador, leia o arquivo linha a linha e escreva cada linha no arquivo de destino, pulando a linha que deve ser excluída do resultado.

import os

mat = '20201299384'  #  Para localizar a linha

with open('arquivo.txt', 'r', encoding = 'utf-8') as arq, \
    open('arquivo.txt.tmp', 'w', encoding = 'utf-8') as saida:
    for linha in arq:
        #  Use qualquer critério para encontrar a linha
        if linha.split()[0] != mat:
            saida.write(linha)

os.replace('arquivo.txt.tmp', 'arquivo.txt')Code language: Python (python)

Se o arquivo original for pequeno, coloque todo o seu conteúdo em uma lista na memória usando o método readlines(). Depois, remova da lista o elemento correspondente à linha que deve ser apagada e salve a lista no novo arquivo.

import os

mat = '20201299384'  #  Para localizar a linha

with open('arquivo.txt', 'r', encoding = 'utf-8') as arq, \
    open('arquivo.txt.tmp', 'w', encoding = 'utf-8') as saida:
    texto = arq.readlines()
    remover = [linha for linha in texto if mat in linha]
    for elem in remover:
        texto.remove(elem)
    
    saida.write(''.join(texto))

os.replace('arquivo.txt.tmp', 'arquivo.txt')Code language: Python (python)

Esses métodos também funcionam se você quiser alterar o conteúdo de uma linha ou adicionar uma nova linha no meio do arquivo.

Para isso, é só alterar a forma de tratar a linha nos exemplos acima, editando a string ou o elemento da lista correspondente à linha.

Conclusão

Além de entender a diferença entre um arquivo texto e um arquivo binário, nesse post você aprendeu como abrir um arquivo para leitura ou edição em Python.

Não se esqueça de que os arquivos podem crescer demais com o tempo e que os usuários podem ter acesso para editar os arquivos direto no sistema operacional.

Portanto, use as boas práticas que eu apresentei aqui para manipular o conteúdo de arquivos texto e sempre considere o cenário de uso atual e futuro.

Você tem alguma outra situação em que precisa manipular um arquivo? Então escreva nos comentários e ajude a melhorar esse post!

Guilherme Brügger D Amato - Audiência Pública na Comissão Senado do Futuro

Guilherme Brügger D’Amato é servidor concursado de TI na Câmara dos Deputados, onde ocupou o cargo de Diretor de Informática entre 2015 e 2016. Com mais de 26 anos de experiência como programador e executivo de TI, já desenvolveu sites e sistemas usados por dezenas de milhões de pessoas. Conecte-se com ele no LinkedIn ou no Instagram.

Deixe um comentário