CSE 111: Programação com Funções

S05 - Atividade de Aprendizagem (1 de 2): Arquivos de Texto

A maioria dos computadores armazena permanentemente grandes quantidades de dados em dispositivos como discos rígidos, unidades de estado sólido e pen drives. Os dados armazenados nesses dispositivos são organizados em arquivos. Assim como uma pessoa pode escrever palavras em um papel, um computador pode armazenar palavras e outros dados em um arquivo. Nesta lição, você aprenderá a criar programas em Python que leem arquivos de texto.

Conceitos

Em termos gerais, existem dois tipos de arquivos: arquivos de texto e arquivos binários. Um arquivo de texto armazena palavras e números como texto legível por humanos. Um arquivo binário armazena imagens, diagramas, sons, músicas, filmes e outras mídias como números em um formato que não é diretamente legível por humanos.

Arquivos de Texto

Para ler dados de um arquivo de texto, o arquivo deve existir em uma das unidades do computador, e seu programa deve fazer estas três coisas:

  1. Abrir o arquivo para ler o texto
  2. Ler o arquivo, geralmente uma linha de texto por vez
  3. Fechar o arquivo

A função integrada open abre um arquivo para leitura ou gravação. Aqui está um trecho da documentação oficial da função open:

open(filename, mode="rt", encoding="utf-8")

Abre um arquivo e retorna um objeto de arquivo correspondente.

filename é o nome do arquivo a ser aberto.

mode é uma string opcional que especifica o modo em que o arquivo será aberto. O padrão é "rt", que significa aberto para leitura em modo de texto. Outros valores comuns são "wt" para escrever um arquivo de texto (truncando o arquivo se ele já existir) e "at" para anexar ao final de um arquivo de texto.

O exemplo 1 contém um programa que, na linha 20, abre um arquivo de texto chamado plantas.txt para leitura. Na linha 23, há um loop for que lê o texto do arquivo uma linha por vez e repete o corpo do loop para cada linha. No corpo do loop, entre as linhas 24–29, o código remove os espaços em branco ao redor (se houver) e armazena cada linha de texto em uma lista.

# Exemplo 1
def main():
    # Lê o conteúdo de um arquivo de texto
    # chamado plantas.txt em uma lista.
    lista_de_texto = lista_de_leitura("plantas.txt")
    # Exibe a lista inteira.
    print(lista_de_texto)
def lista_de_leitura(nomedoarquivo):
    """Lê o conteúdo de um arquivo de texto em uma lista e
    retorna a lista. Cada elemento da lista conterá
    uma linha de texto do arquivo de texto.
    Parâmetro filename: o nome do arquivo de texto a ser lido
    Retorno: uma lista de strings
    """
    # Cria uma lista vazia que armazenará
    # as linhas de texto do arquivo de texto.
    lista_de_texto = []
    # Abre o arquivo de texto para leitura e armazena uma referência
    # para o arquivo aberto em uma variável chamada arquivo_de_texto.
    with open(nomedoarquivo, "rt", encoding="utf-8") as arquivo_de_texto:
        # Lê o conteúdo do arquivo
        # de texto uma linha de cada vez.
        for linha in arquivo_de_texto:
            # Remove os espaços em branco, se houver,
            # do início e do fim da linha.
            linha_limpa = linha.strip()
            # Adiciona a linha limpa do texto
            # ao final da lista.
            lista_de_texto.append(linha_limpa)
    # Retorna a lista que contém as linhas de texto.
    return lista_de_texto
# Chama main para iniciar este programa.
if __name__ == "__main__":
    main()
> python exemplo_1.py
['baobá', 'anigozanthos', 'eucalipto', 'helicônia', 'tulipa',
'cacto chupasangre', 'opúncia', 'ginkgo biloba']

Após ler um arquivo com um loop for, poderíamos fechá-lo manualmente com file.close(). Porém, ao usar open dentro de um bloco with para abrir o arquivo, o loop for fica dentro desse bloco e, ao final, o próprio Python fecha o arquivo automaticamente, dispensando file.close().

Arquivos CSV

Muitos sistemas de computador importam e exportam dados em arquivos CSV. CSV é uma sigla em inglês que significa "valores separados por vírgula". Um arquivo CSV é um arquivo de texto que organiza dados em forma de tabela: cada linha do arquivo corresponde a um registro e cada coluna é separada por vírgula. O exemplo a seguir mostra o conteúdo de um arquivo CSV chamado hinos.csv que armazena dados sobre músicas religiosas. Observe que a primeira linha do arquivo contém o cabeçalho das colunas, as próximas quatro linhas contêm dados sobre quatro hinos e cada linha contém três colunas separadas por vírgulas.

Nome,Autor,Compositor
Erguei-vos Cantando, John Wade, John Wade
Anjos Descem a Cantar, French Carol, French Carol
Noite Feliz, Joseph Mohr, Franz Gruber
No Dia de Natal, Laudis Corona, Laudis Corona

O Python possui um módulo padrão chamado csv que inclui funcionalidade para ler e escrever em arquivos CSV. O programa no exemplo 2 mostra como abrir um arquivo CSV e usar o módulo csv para ler os dados e exibi-los em uma janela de terminal.

No exemplo 2, na linha 6, há uma chamada para a função integrada open do Python, que abre o arquivo hinos.csv para leitura. Na linha 9, o programa cria um objeto csv.reader que lerá o arquivo hinos.csv. Dentro do loop for nas linhas 12 e 13, o csv.reader lê e exibe cada linha do arquivo CSV.

# Exemplo 2
import csv
def main():
    # Abre o arquivo CSV para leitura e armazena uma referência
    # para o arquivo aberto em uma variável chamada arquivo_csv.
    with open("hinos.csv", "rt", encoding="utf-8") as arquivo_csv:
        # Usa o módulo csv para criar um objeto leitor
        # que será lido do arquivo CSV aberto.
        leitor = csv.reader(arquivo_csv)
        # Lê as linhas no arquivo CSV uma de cada vez.
        # O objeto leitor retorna cada linha como uma lista.
        for lista_da_linha in leitor:
            print(lista_da_linha)
# Chama main para iniciar este programa.
if __name__ == "__main__":
    main()
> python exemplo_2.py
['Nome', 'Autor', 'Compositor']
['Erguei-vos Cantando', 'John Wade', 'John Wade']
['Anjos Descem a Cantar', 'French Carol', 'French Carol']
['Noite Feliz', 'Joseph Mohr', 'Franz Gruber']
['No Dia de Natal', 'Laudis Corona', 'Laudis Corona']

Quando um csv.reader lê uma linha de um arquivo CSV, o leitor retorna a linha como uma lista de strings. A saída do exemplo 2 mostra que um csv.reader retorna uma lista de strings. Na saída, observe as cinco listas de strings (strings entre colchetes [ … ]) que foram impressas pela instrução print na linha 17. Observe também que o leitor lê todas as linhas de um arquivo CSV, inclusive a primeira linha, que contém o cabeçalho das colunas.

Você deve se lembrar que no CSE 110, você escreveu um programa que lê um arquivo CSV sem usar um csv.reader. Esse programa dividiu cada linha de texto do arquivo CSV usando o método de divisão de string, split. Infelizmente, usar o método split não funcionará para todos os arquivos CSV. Considere o seguinte arquivo hinos.csv que contém linhas para os hinos "Lá na Judéia, Onde Cristo Nasceu" e "Mundo Feliz, Nasceu Jesus". Ambos os hinos têm vírgulas nos nomes. Se usarmos o método split para separar as colunas neste arquivo CSV, os nomes dos hinos serão divididos. Um csv.reader dividirá corretamente as linhas em todos os arquivos CSV válidos.

Nome,Autor,Compositor
"Lá na Judéia, Onde Cristo Nasceu",John Mcfarlane,John Mcfarlane
"Mundo Feliz, Nasceu Jesus",John Wade,John Wade
"Pequena Vila de Belém", Phillips Brooks, Lewis Redner

Processando Cada Linha em Arquivo CSV

Depois de ler cada linha de um arquivo CSV, o loop for no exemplo anterior simplesmente exibe a lista de linhas em uma janela de terminal. É claro que um loop for pode fazer muito mais do que simplesmente exibir cada linha. Considere o seguinte arquivo CSV chamado dentistas.csv que armazena dados sobre consultórios odontológicos. Observe que a primeira linha do arquivo contém o cabeçalho das colunas, as próximas quatro linhas contêm dados sobre quatro consultórios de dentistas e cada linha contém cinco colunas separadas por vírgulas.

Nome da Empresa, Endereço, Telefone, Funcionários, Pacientes
Sorriso Perfeito Odontologia, Rua das Palmeiras 556, (99) 9990-9990, 7, 1205
Prime Oral Clínica Dental, Rua das Laranjeiras 33, (99) 1234-5678, 10, 1520
Viva Bem Odontologia, Rua São João 106, (99) 8765-4321, 12, 1982
Odonto Família Brasil, Rua Central 44, (99) 9999-9999, 8, 1453

O programa no exemplo 3 processa cada linha no arquivo dentistas.csv para determinar qual consultório tem mais pacientes por funcionário. Observe que a primeira linha do arquivo dentistas.csv contém o cabeçalho da coluna. O cabeçalho não contêm números e não são necessários para os cálculos, então o programa pula a primeira linha chamando a função integrada next na linha 18.

# Exemplo 3
import csv
# Índices de algumas das colunas
# no arquivo dentistas.csv.
INDICE_NOME_DA_EMPRESA = 0
INDICE_NUM_DE_FUNC = 3
INDICE_NUM_DE_PACIENTES = 4
def main():
    # Abre um arquivo chamado dentistas.csv e armazena uma referência
    # para o arquivo aberto em uma variável chamada arquivo_de_dentistas.
    with open("dentistas.csv", "rt", encoding="utf-8") as arquivo_de_dentistas:
        # Usa o módulo csv para criar um objeto
        # leitor que será lido do arquivo aberto.
        leitor = csv.reader(arquivo_de_dentistas)
        # Como a primeira linha do arquivo CSV contém apenas o cabeçalho
        # (nomes das colunas), usamos next(leitor) para avançar uma linha
        # e começar a leitura diretamente pelos dados dos dentistas.
        next(leitor)
        max_registrado = 0
        maior_consultorio = None
        # Lê as linhas no arquivo CSV, uma de cada vez.
        # O objeto leitor retorna cada linha como uma lista.
        for lista_da_linha in leitor:
            # Para a linha atual, recupere os
            # valores nas colunas 0, 3 e 4.
            empresa = lista_da_linha[INDICE_NOME_DA_EMPRESA ]
            num_de_funcionarios = int(lista_da_linha[INDICE_NUM_DE_FUNC])
            num_de_pacientes = int(lista_da_linha[INDICE_NUM_DE_PACIENTES])
            # Calcula o número de pacientes por
            # funcionário do consultório atual.
            pacientes_por_funcionario = num_de_pacientes / num_de_funcionarios
            # Se o consultório atual tiver mais
            # pacientes por funcionário do que o número registrado
            # máximo, atribui max_registrado e maior_consultorio
            # para ser o atual consultório.
            if pacientes_por_funcionario > max_registrado:
                max_registrado = pacientes_por_funcionario
                maior_consultorio = empresa
    # Exibe os resultados para o usuário.
    print(f"{maior_consultorio} tem {max_registrado:.1f}"
            " pacientes por funcionário")
# Chama main para iniciar este programa.
if __name__ == "__main__":
    main()
> python exemplo_3.py
Odonto Família Brasil tem 181.6 pacientes por funcionário    

Lendo um Arquivo CSV em Uma Lista Composta

O programa no exemplo 3 lê e processa cada linha em um arquivo CSV. Ele precisa acessar os dados em cada linha apenas uma vez. Se um programa precisar acessar o conteúdo de um arquivo CSV várias vezes, ele poderá ler o conteúdo do arquivo em uma lista composta e, então, acessar os dados da lista. O programa no exemplo 4 contém uma função chamada ler_lista_composta que lê o conteúdo de um arquivo CSV em uma lista composta.

# Exemplo 4
import csv
def main():
    # Lê o conteúdo do arquivo dentistas.csv
    # em uma lista composta.
    lista_de_dentistas = ler_lista_composta("dentistas.csv")
    # Exibe a lista inteira.
    print(lista_de_dentistas)
def ler_lista_composta(nomedoarquivo):
    """Lê o conteúdo de um arquivo CSV em uma lista 
    composta e retorna a lista. Cada elemento na
    lista composta será uma pequena lista que contém
    os valores de uma linha do arquivo CSV.
    Parâmetro filename: o nome do arquivo CSV a ser lido
    Retorno: uma lista de listas que contêm strings
    """
    # Cria uma lista vazia que armazenará
    # os dados do arquivo CSV.
    lista_composta = []
    # Abre o arquivo CSV para leitura e armazena uma referência
    # para o arquivo aberto em uma variável chamada arquivo_csv.
    with open(nomedoarquivo, "rt", encoding="utf-8") as arquivo_csv:
        # Usa o módulo csv para criar um objeto leitor
        # que será lido do arquivo CSV aberto.
        leitor = csv.reader(arquivo_csv)
        # Lê as linhas no arquivo CSV uma de cada vez.
        # O objeto leitor retorna cada linha como uma lista.
        for lista_da_linha in leitor:
            # Se a linha atual não estiver em branco,
            # anexa a linha à lista_composta.
            if len(lista_da_linha) != 0:
                # Adiciona uma linha do arquivo CSV
                # à lista composta.
                lista_composta.append(lista_da_linha)
    # Retorna a lista composta.
    return lista_composta
# Chama main para iniciar este programa.
if __name__ == "__main__":
    main()
> python exemplo_4.py
[['Nome da Empresa', 'Endereço', 'Número de Telefone', 'Funcionários', 'Pacientes'],
 ['Sorriso Perfeito Odontologia', 'Rua das Palmeiras 556', '(99) 9990-9990', '7', '1205'],
 ['Prime Oral Clínica Dental', 'Rua das Laranjeiras 33', '(99) 1234-5678', '10', '1520'],
 ['Viva Bem Odontologia', 'Rua Maria Paula 106', '(99) 8765-4321', '12', '1982'],
 ['Odonto Família Brasil', 'Rua Central 44', '(99) 9999-9999', '8', '1453']]

Lendo um Arquivo CSV em Um Dicionário Composto

Se os valores em uma das colunas de um arquivo CSV forem únicos, um programa poderá ler o conteúdo de um arquivo CSV em um dicionário composto e então usar o dicionário para encontrar dados rapidamente. Lembre-se de que cada item em um dicionário é um par de chave-valor. Os valores da coluna exclusiva em um arquivo CSV serão as chaves no dicionário. O programa no exemplo 5 mostra como ler os dados de um arquivo CSV em um dicionário composto. Observe no exemplo 5, por causa das linhas 6, 10, 44 e 47, que o programa usa os números de telefone do consultório odontológico como chaves no dicionário.

# Exemplo 5
import csv
def main():
    # Índice da coluna de números de telefone
    # no arquivo dentistas.csv.
    INDICE_TELEFONES = 2
    # Lê o conteúdo de dentistas.csv em um
    # dicionário composto chamado dic_de_dentistas. Usa
    # os números de telefone como chaves no dicionário.
    dic_de_dentistas = ler_dicionario("dentistas.csv", INDICE_TELEFONES)
    # Exibe o dicionário composto dos dentistas.
    print(dic_de_dentistas)
def ler_dicionario(nomedoarquivo, indice_da_coluna_de_chaves):
    """Lê o conteúdo de um arquivo CSV em um dicionário
    composto e retorna o dicionário.
    Parâmetros
        nomedoarquivo: o nome do arquivo CSV a ser lido.
        indice_da_coluna_de_chaves: o índice da coluna
            para usar como chaves no dicionário.
    Retorno: um dicionário composto com
        o conteúdo do arquivo CSV.
    """
    # Cria um dicionário vazio que armazenará
    # os dados do arquivo CSV.
    dicionario = {}
    # Abre o arquivo CSV para leitura e armazena uma referência
    # para o arquivo aberto em uma variável chamada arquivo_csv.
    with open(nomedoarquivo, "rt", encoding="utf-8") as arquivo_csv:
        # Usa o módulo csv para criar um objeto leitor
        # que será lido do arquivo CSV aberto.
        leitor = csv.reader(arquivo_csv)
        # A primeira linha do arquivo CSV contém o cabeçalho
        # das colunas, e não dados, então esta instrução ignora
        # a primeira linha do arquivo CSV.
        next(leitor)
        # Lê as linhas no arquivo CSV uma de cada vez.
        # O objeto leitor retorna cada linha como uma lista.
        for lista_da_linha in leitor:
            # Se a linha atual não estiver em branco, adiciona os
            # dados do atual para o dicionário.
            if len(lista_da_linha) != 0:
                # Da linha atual, recupera os dados
                # da coluna que contém a chave.
                chave = lista_da_linha[indice_da_coluna_de_chaves]
                # Armazena os dados da linha atual
                # no dicionário.
                dicionario[chave] = lista_da_linha
    # Retorna o dicionário.
    return dicionario
# Chama main para iniciar este programa.
if __name__ == "__main__":
    main()
> python exemplo_5.py
{'(99) 9990-9990': ['Sorriso Perfeito Odontologia', 'Rua das Palmeiras 556', '(99) 9990-9990', 7, 1205],
 '(99) 1234-5678': ['Prime Oral Clínica Dental', 'Rua das Laranjeiras 33', '(99) 1234-5678', 10, 1520],
 '(99) 8765-4321': ['Viva Bem Odontologia', 'Rua Maria Paula 106', '(99) 8765-4321', 12, 1982],
 '(99) 9999-9999': ['Odonto Família Brasil', 'Rua Central 44', '(99) 9999-9999', 8, 1453]}

Informações Adicionais

Os tutoriais a seguir contêm informações adicionais que podem ser úteis. A leitura desses tutoriais não é obrigatória.

Resumo

Um arquivo de texto armazena palavras e números como texto legível por humanos. Durante esta semana, você aprenderá a escrever código Python para ler arquivos de texto. Para fazer isso, seu programa deve primeiro abrir o arquivo chamando a função embutida open. É recomendável fazer isso dentro de um bloco with, pois o arquivo será fechado automaticamente quando o bloco terminar, evitando que você precise fechá-lo manualmente.

Um arquivo CSV é um arquivo de texto que contém linhas e colunas de dados. CSV é uma sigla em inglês que significa "valores separados por vírgula". Dentro de cada linha em um arquivo CSV, os valores de dados são separados por vírgulas. O Python inclui um módulo padrão chamado csv que nos ajuda a escrever facilmente código para ler arquivos CSV. Às vezes, um programa simplesmente precisa usar os valores de um arquivo CSV em cálculos, então escrevemos código Python para realizar cálculos para cada linha. Outras vezes, escrevemos código Python para ler o conteúdo de um arquivo CSV em uma lista composta ou dicionário composto.

Atividade

Finalidade

Avalie seu conhecimento sobre arquivos de texto e listas escrevendo um programa que lê o conteúdo de um arquivo de texto em uma lista e, em seguida, altera alguns dos valores na lista.

Documentação Útil

Tarefa

Siga os passos abaixo para configurar o VS Code e fazer com que seu programa leia um arquivo de texto:

  1. Baixe o arquivo provincias.txt e salve-o na mesma pasta onde você salvará seu programa Python.
  2. Usando o VS Code, abra a pasta onde você salvou o arquivo provincias.txt fazendo o seguinte:
    • Em um computador com o sistema operacional macOS:
      1. Selecione o menu Arquivo e depois Abrir pasta...
      2. Localize e selecione a pasta onde você salvou o arquivo provincias.txt.
      3. Selecione o botão Abrir.
    • Em um computador com o sistema operacional Windows:
      1. Selecione o menu Arquivo e depois Abrir pasta...
      2. Localize e selecione a pasta onde você salvou o arquivo provincias.txt.
      3. Selecione o botão Selecionar Pasta.

Agora que você configurou corretamente o VS Code para que seu programa possa ler o arquivo provincias.txt, abra esse arquivo no VS Code e examine-o. Observe que o arquivo contém uma lista de nomes de províncias canadenses. Observe também que o arquivo contém "AB" várias vezes, que é uma abreviação de Alberta.

Escreva um programa Python chamado provincias.py que leia o conteúdo de provincias.txt em uma lista e depois modifique essa lista. Seu programa deve fazer o seguinte:

  1. Abrir o arquivo provincias.txt para leitura.
  2. Ler o conteúdo do arquivo em uma lista onde cada linha de texto no arquivo é armazenada em um elemento separado na lista.
  3. Exibir a lista inteira.
  4. Remover o primeiro elemento da lista.
  5. Remover o último elemento da lista.
  6. Substitua todas as ocorrências de "AB" na lista por "Alberta".
  7. Conte o número de elementos que são "Alberta" e exiba esse número.

Procedimento de Teste

Verifique se seu programa funciona corretamente seguindo cada etapa deste procedimento de teste:

  1. Execute seu programa e certifique-se de que a saída dele corresponda à saída abaixo. (Seu programa pode encapsular os nomes das províncias de forma diferente.)
    > python provincias.py
    ['Alberta', 'Ontário', 'Ilha do Príncipe Eduardo', 'Ontário',
    'Quebec', 'Saskatchewan', 'AB', 'Nova Escócia', 'Alberta',
    'Territórios do Noroeste', 'Saskatchewan', 'Nunavut',
    'Nova Escócia', 'Ilha do Príncipe Eduardo', 'Alberta',
    'Nova Escócia', 'Nova Escócia', 'Ilha do Príncipe Eduardo',
    'Colúmbia Britânica', 'Ontário', 'Ontário',
    'Terra Nova e Labrador', 'Ontário', 'Ontário',
    'Saskatchewan', 'Nova Escócia', 'Ilha do Príncipe Eduardo',
    'Saskatchewan', 'Ontário', 'Terra Nova e Labrador',
    'Ontário', 'Colúmbia Britânica', 'Manitoba', 'Ontário',
    'Alberta', 'Saskatchewan', 'Ontário', 'Yukon', 'Ontário',
    'Nova Brunswick', 'Colúmbia Britânica', 'Manitoba', 'Yukon',
    'Colúmbia Britânica', 'Manitoba', 'Yukon',
    'Terra Nova e Labrador', 'Ontário', 'Yukon', 'Ontário',
    'AB', 'Nova Escócia', 'Terra Nova e Labrador', 'Yukon',
    'Nunavut', 'Territórios do Noroeste', 'Nunavut', 'Yukon',
    'Colúmbia Britânica', 'Ontário', 'AB', 'Saskatchewan',
    'Ilha do Príncipe Eduardo', 'Saskatchewan',
    'Ilha do Príncipe Eduardo', 'Alberta', 'Ontário', 'Al]
    
    Alberta aparece 9 vezes na lista modificada.

Exemplo de Solução

Quando terminar seu programa, consulte o exemplo de solução para comparar com o seu.

Primeiro, procure concluir o programa sem olhar o exemplo de solução. No entanto, se já tiver trabalhado nele por bastante tempo e ainda estiver com dificuldades, sinta-se à vontade para usá-lo como apoio para finalizar seu programa.

Envio

Continue para a próxima atividade.

Links Úteis:

>