Lendo Dados de Arquivos

Visão Geral

Perguntas
  • Como posso carregar o conteúdo de um arquivo no Python?

  • Como eu posso processar muitos arquivos com um único comando?

Objetivos
  • Conseguir carregar o conteúdo de um arquivo em uma string ou lista.

  • Conseguir converter dados carregados como strings em valores numéricos.

  • Conseguir escrever valores carregados no Python em um novo arquivo.

  • Ser capaz de escrever expressões de globbing que correspondem a um conjunto de arquivos.

  • Usar glob para criar listas de arquivos.

  • Escrever for loops para executar operações em arquivos, dados seus nomes em uma lista.

Use a função embutida open para ler arquivos em uma string.

Para ler um arquivo, usamos a expressão with open(...) as f, onde f é a variável na qual vamos carregar o conteúdo do arquivo em uma string. Segue a mesma estrutura de um loop for:

with open('data/consumos/consumos_00.txt') as f:
    string_de_dados = f.read()

print(string_de_dados)

O uso do with ... não é obrigatório, mas é recomendado. Podemos abrir e fechar arquivos uma linha por vez. O bloco de código a seguir é equivalente ao anterior:

arquivo_de_entrada = open('data/consumos/consumos_00.txt')
string_de_dados = arquivo_entrada.read()
arquivo_de_entrada.close()

print(string_de_dados)

Use read para carregar um arquivo como uma string.

A variável f vai ter um método .read que permite carregar os dados como uma string. Repare que a variável f poderia se chamar qualquer coisa:

with open('data/consumos/consumos_00.txt') as arquivo_entrada:
    string_de_dados = arquivo_entrada.read()

print(type(string_de_dados))

Use readlines para carregar um arquivo como uma lista de linhas.

Ler um arquivo como string pode ser útil, mas muitas vezes queremos criar coleções de valores (listas) com o conteúdo do arquivo. O método readlines carrega o conteúdo do arquivo em uma lista, na qual cada elemento é uma linha do arquivo.

with open('data/consumos/consumos_00.txt') as f:
    lista_de_dados = f.readlines()

print(type(lista_de_dados))

Os caracteres '\t' e '\n' simbolizam espaços em branco.

Diferente da nossa string_de_dados, se imprimirmos nossa lista, o resultado não é muito bonito:

print(lista_de_dados)

Isso acontece por que cada linha do nosso arquivo (e cada elemento na nossa lista) é uma string, e não um número. Essas strings possuem o caracter '\n' no final. Esse caracter é utilizado para simbolizar um espaço de nova linha:

print("Uma linha com espaço no final.\nOutra linha.")

O caracter TAB também simboliza um espaço em branco, mas de um TAB, ou parágrafo:

print("Antes do TAB:\tDepois.")

Recuperando Valores Numéricos

Para poder fazer operações numéricas com o conteúdo desses arquivos, precisamos de valores de tipo numéricos, e não strings.
Utilize conversão de tipos e o padrão acumulador para carregar o conteúdo do arquivo consumos_00.txt em uma lista de floats.

Solução

lista_floats = []
with open("data/consumos/consumos_00.txt") as f:
    lista_strings = f.readlines()

for linha in lista_strings:
    lista_floats.append(float(linha))

Removendo espaços em branco

No exercício anterior, usamos conversão de tipos para converter as strings que carregamos do arquivo para remover o espaço em branco ('\n'). No entanto, as strings também tem os métodos strip que podem fazer isso.

linha_um = "\nUma linha com espaço em branco no início e fim.\n\n\n"
linha_dois = "\nOutra linha, com espaço em branco no início."
print(linha_um + linha_dois)

Uma linha com espaço em branco no início e fim.



Outra linha, com espaço em branco no início.

Se aplicarmos o método strip na linha_um, removemos o espaço em branco do início e final da linha.:

linha_um = "\nUma linha com espaço em branco no início e fim.\n\n\n"
linha_dois = "\nOutra linha, com espaço em branco no início."
print(linha_um.strip() + linha_dois)
Uma linha com espaço em branco no início e fim.
Outra linha, com espaço em branco no início.

Também existe o método lstrip para somente para espaços no início da linha, e rstrip somente para espaços no fim:

linha_um = "\nUma linha com espaço em branco no início e fim.\n\n\n"
linha_dois = "\nOutra linha, com espaço em branco no início."
print(linha_um.rstrip() + linha_dois.lstrip())

Uma linha com espaço em branco no início e fim.Outra linha, com espaço em branco no início.

Use um for loop para processar arquivos dada uma lista com seus nomes.

lista_de_arquivos = [
    "data/consumos/consumos_00.txt",
    "data/consumos/consumos_01.txt",
    "data/consumos/consumos_02.txt",
    "data/consumos/consumos_03.txt",
    "data/consumos/consumos_04.txt",
]

for arquivo in lista_de_arquivos:
    numeros = []
    with open(arquivo) as f:
        linhas = f.readlines()

    print("Nome do arquivo:", arquivo)
    print("Número de medições:", len(linhas))
    print("\n")
Nome do arquivo: data/consumos/consumos_00.txt
Número de medições: 54

Nome do arquivo: data/consumos/consumos_01.txt
Número de medições: 81

Nome do arquivo: data/consumos/consumos_02.txt
Número de medições: 70

Nome do arquivo: data/consumos/consumos_03.txt
Número de medições: 52

Nome do arquivo: data/consumos/consumos_04.txt
Número de medições: 62

No entanto, ter que criar manualmente a lista de arquivos pode ser bem custoso. Existem soluções práticas para isso.

Use glob.glob para encontrar conjuntos de arquivos cujos nomes correspondam a um padrão.

import glob
print('Todos os arquivos zippados no diretório `data`:', glob.glob('data/*.zip'))
['data/consumos.zip']

Encontre os Arquivos

Modifique o código acima para encontrar todos os arquivos com dados de consumos. Como podemos modificar essa busca para encontrar somente os arquivos 00 até 09?

Solução

Existem muitas buscas que podem dar certo, mas uma simples e direta é:

# Todos os arquivos
glob.glob("data/consumos/*.txt")
# De 00 até 09
glob.glob("data/consumos/consumos_0*.txt")

Use glob e for para processar lotes de arquivos.

for arquivo in glob("data/consumos/*.txt"):
    numeros = []
    with open(arquivo) as f:
        linhas = f.readlines()

    print("Nome do arquivo:", arquivo)
    print("Número de medições:", len(linhas))
    print("\n")

Processando Lotes de Arquivos

Usando glob e um for loop, escreva um programa que:

  1. Calcule o número de medições em cada arquivo.
  2. Calcule o menor e maior consumo e cada arquivo.
  3. Imprima tudo em um loop.

Depois que conseguir, modifique seu código para imprimir:

  • O nome do arquivo com mais registros.
  • O nome do arquivo com o maior valor (e o valor.)
  • O nome do arquivo com o menor valor (e o valor.)

Solução

lista_de_arquivos = glob("data/consumos/*.txt")

for arquivo in lista_de_arquivos:
    numeros = []
    with open(arquivo) as f:
        linhas = f.readlines()
        for numero in linhas:
            numeros.append(float(numero))

    menor_consumo = min(numeros)
    maior_consumo = max(numeros)

    print("Nome do arquivo:", arquivo)
    print("Número de medições:", len(numeros))
    print("Consumo máximo:", maior_consumo)
    print("Consumo mínimo:", menor_consumo)
    print("\n")

Adicionando as outras métricas:

lista_de_arquivos = glob("data/consumos/*.txt")

arquivo_mais_registros = ""
arquivo_maximo_consumo = ""
arquivo_minimo_consumo = ""
mais_registros = 0
maximo_consumo = 0
minimo_consumo = 0

for arquivo in lista_de_arquivos:
    numeros = []
    with open(arquivo) as f:
        linhas = f.readlines()
        for numero in linhas:
            numeros.append(float(numero))
    
    n_medicoes = len(numeros)
    maior_consumo = max(numeros)
    menor_consumo = min(numeros)
    if n_medicoes > mais_registros:
        mais_registros = n_medicoes
        arquivo_mais_registros = arquivo
    
    if maior_consumo > maximo_consumo:
        maximo_consumo = maior_consumo
        arquivo_maximo_consumo = arquivo
    
    if minimo_consumo == 0 or menor_consumo < minimo_consumo:
        minimo_consumo = menor_consumo
        arquivo_minimo_consumo = arquivo

print("Arquivo com mais medições:", arquivo_mais_registros, "com", mais_registros, "medições.")
print("Arquivo com maior valor:", arquivo_maximo_consumo, maximo_consumo)
print("Arquivo com menor valor:", arquivo_minimo_consumo, minimo_consumo)
print("\n")
Arquivo com mais medições: data/consumos/consumos_24.txt com 100 medições.
Arquivo com maior valor: data/consumos/consumos_25.txt 117.99
Arquivo com menor valor: data/consumos/consumos_23.txt 69.0

Pontos-chave

  • Use a função embutida open para ler arquivos.

  • Use read para carregar um arquivo como uma string.

  • Use readlines para carregar um arquivo como uma lista de linhas.

  • Os caracteres ' ' e ' ' simbolizam espaços em branco.

  • Use a função open(..., mode='w') para escrever em arquivos.

  • Use um for loop para processar arquivos dada uma lista com seus nomes.

  • Use glob.glob para encontrar conjuntos de arquivos cujos nomes correspondam a um padrão.

  • Use glob e for para processar lotes de arquivos.