MAC2166 - Introdução à Computação

13/05/2014 - Aula 13

Leitura de Arquivos

Nos exercícios que fizemos no curso até a aula de hoje, sempre criamos programas que manipulavam dados digitados pelos usuários. Entretanto, essa não é a unica forma de entrada de dados que podemos usar em um programa. Uma outra forma de entrada de dados usada com frequência em programas é a leitura de dados gravados em um arquivo.

Para abrir um arquivo para leitura, podemos usar a função open(), passando como parâmetros para ela o nome (com caminho, se necessário) do arquivo a ser aberto e a string 'r' (de read, para indicar que o arquivo será aberto para leitura). A função devolve um objeto do tipo file.

Para ler as linhas de um arquivo já aberto, podemos usar o comando for var_linha in arquivo:, onde var_linha é o nome da variável que armazenará o conteúdo de uma linha e var_arquivo é o arquivo já aberto para leitura. Depois que o uso de um arquivo já tiver sido encerrado, é preciso fechar o arquivo por meio da função close().

Veja o exemplo a seguir, que abre um arquivo chamado 'meu_arquivo_utf8.txt', lê cada linha do arquivo e a imprime.

In [1]:
nome_do_arquivo = "meu_arquivo_utf8.txt"
arquivo = open(nome_do_arquivo, 'r', encoding="utf8")  # abre o arquivo para leitura

print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)
for linha in arquivo:      # percorre cada linha do arquivo
    print(linha,end="")    # imprime uma linha
    
arquivo.close()  # depois do uso, fecha o arquivo
Conteúdo do arquivo 'meu_arquivo_utf8.txt'

    Para ser grande, sê inteiro: nada
    Teu exagera ou exclui.
    Sê todo em cada coisa. Põe quanto és
    No mínimo que fazes.
    Assim em cada lago a lua toda
    Brilha, porque alta vive.

        Ricardo Reis, 14-2-1933 
        (heterônimo de Fernando Pessoa)	


No exemplo acima, passamos um terceiro parâmetro para a função open(), o parâmetro chamado encoding. Esse parâmetro é opcional; quando não passamos nenhum valor para ele, o valor usado é a codificação padrão do Python 3, que é 'utf8'. Um outro valor possível para o parâmetro encoding é o 'latin1'.

Quando tentamos abrir para leitura um arquivo que não existe, a função gera o erro FileNotFoundError, como mostrado abaixo:

In [2]:
nome_do_arquivo = "bla_bla.txt"  # nome que não corresponde a um arquivo existente
arquivo = open(nome_do_arquivo, 'r')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-2-abf2101a88d2> in <module>()
      1 nome_do_arquivo = "bla_bla.txt"  # nome que não corresponde a um arquivo existente
----> 2 arquivo = open(nome_do_arquivo, 'r')

FileNotFoundError: [Errno 2] No such file or directory: 'bla_bla.txt'

"Captura" e "Tratamento" de Exceções

No "esqueleto" do EP3, há um exemplo de leitura de arquivo, na função leitura_dos_dados(), que lê um arquivo contendo medições metereológicas e gera uma tabela (matriz) contendo os dados lidos do arquivo. A função pede que o usuário digite o nome do arquivo a ser aberto, mas caso o usuário digite um nome de arquivo que não existe, em vez da execução da função ser interrompida pelo erro FileNotFound (gerado pela tentativa de abertura do arquivo), a função pede para que o usuário digite novamente um nome de arquivo e tenta abri-lo novamente. A função repete essas operações até que o usuário digite o nome de arquivo que exista.

Mas como a função leitura_dos_dados() dos dados é capaz de fazer isso? Mais especificamente, como ela evita que a execução do programa seja interrompida quando o erro FileNotFound acontece?

Ela faz isso por meio do comando para tratamento de exceções try . Veja um exemplo de uso do try a seguir:

In [3]:
# Lê o nome do arquivo de dados e o abre para leitura
abriu = False
while not abriu:
    nome_do_arquivo = input("Digite o nome do arquivo de dados: ")
    
    try: 
        arquivo = open(nome_do_arquivo, 'r') 
    except FileNotFoundError:
        print(nome_do_arquivo, " não encontrado. Você digitou direito?")
    else:
        abriu = True
        
print("Conteúdo do arquivo '%s'\n" %nome_do_arquivo)

for linha in arquivo:
    print(linha,end="")
    
arquivo.close()  # depois do uso, fecha o arquivo
Digite o nome do arquivo de dados: arquivo.txt
arquivo.txt  não encontrado. Você digitou direito?
Digite o nome do arquivo de dados: meu_arquivo.txt
meu_arquivo.txt  não encontrado. Você digitou direito?
Digite o nome do arquivo de dados: meu_arquivo_utf8.txt
Conteúdo do arquivo 'meu_arquivo_utf8.txt'

    Para ser grande, sê inteiro: nada
    Teu exagera ou exclui.
    Sê todo em cada coisa. Põe quanto és
    No mínimo que fazes.
    Assim em cada lago a lua toda
    Brilha, porque alta vive.

        Ricardo Reis, 14-2-1933 
        (heterônimo de Fernando Pessoa)	


O Python começa tentando executar o bloco de comandos associado à cláusula try e caso tudo corra bem (no exemplo, se o arquivo existe e foi aberto para leitura com sucesso), então pula o bloco de comandos associado à cláusula except e executa o bloco de comandos associado à cláusula else. Mas se o erro FileNotFound ocorrer durante a execução dos comandos no try, então o bloco de comandos associado à cláusula except é executado e depois o bloco de comandos do else é pulado.

A cláusula else é opcional. Portanto, podemos ter um comando try só com except. Além disso, no except podemos não especificar o tipo de erro que se deseja capturar. Nesse caso, qualquer erro que for gerado durante a execução dos comandos no bloco do try causará a execução dos comandos no bloco do except. Veja outro exemplo a seguir:

In [4]:
divisor = 0
try:
    print("Agora eu vou dividir...")
    divisao = 100 / divisor
    print("Resultado da divisão:", divisao )
except:
    print("Não consegui calcular a divisão!")
    
Agora eu vou dividir...
Não consegui calcular a divisão!

Para saber mais sobre arquivos ...

... consulte as seguintes referências:

E para saber mais sobre tratamento de exceções ...

... consulte a seguinte referência:

Problema 26

Escreva um programa que lê um arquivo e o imprime com as linhas numeradas.

Solução 1

In [6]:
nome_do_arquivo = input("Nome do arquivo: ")
arquivo = open(nome_do_arquivo, 'r', encoding='utf8')
nlin = 1
for linha in arquivo:
    print(nlin, ':', linha)
    nlin += 1
    
Nome do arquivo: meu_arquivo_utf8.txt
1 :     Para ser grande, sê inteiro: nada

2 :     Teu exagera ou exclui.

3 :     Sê todo em cada coisa. Põe quanto és

4 :     No mínimo que fazes.

5 :     Assim em cada lago a lua toda

6 :     Brilha, porque alta vive.

7 : 

8 :         Ricardo Reis, 14-2-1933 

9 :         (heterônimo de Fernando Pessoa)	

10 : 


A impressão gerada pela solução acima não ficou muito boa. As linhas estão separadas por uma linha em branco e os números não ficaram alinhados.

O problema das linhas em branco acontece porque quando lemos cada linha do arquivo, ela já vem com uma quebra de linha no final. E quando usamos o comando print exibir a linha, ele inclui uma outra quebra de linha. Então, para resolver o problema, podemos usar o print passando para ele o parâmetro end='', como mostrado na Solução 2.

Solução 2

In [8]:
nome_do_arquivo = input("Nome do arquivo: ")
arquivo = open(nome_do_arquivo, 'r', encoding='utf8')
nlin = 1
for linha in arquivo:
    print('%4d: %s' %(nlin,linha), end="")
    nlin += 1
Nome do arquivo: meu_arquivo_utf8.txt
   1:     Para ser grande, sê inteiro: nada
   2:     Teu exagera ou exclui.
   3:     Sê todo em cada coisa. Põe quanto és
   4:     No mínimo que fazes.
   5:     Assim em cada lago a lua toda
   6:     Brilha, porque alta vive.
   7: 
   8:         Ricardo Reis, 14-2-1933 
   9:         (heterônimo de Fernando Pessoa)	
  10: 

Agora a impressão ficou correta. :)

Mas temos ainda uma terceira alternativa de solução, que elimina a quebra de linha do final de uma linha lida do arquivo. Essa solução envolve o uso da função rstrip().

Solução 3

In [9]:
nome_do_arquivo = input("Nome do arquivo: ")
arquivo = open(nome_do_arquivo, 'r', encoding='utf8')
nlin = 1
for linha in arquivo:
    linha = linha.rstrip()   # elimina
    print('%4d: %s' %(nlin,linha))
    nlin += 1
Nome do arquivo: meu_arquivo_utf8.txt
   1:     Para ser grande, sê inteiro: nada
   2:     Teu exagera ou exclui.
   3:     Sê todo em cada coisa. Põe quanto és
   4:     No mínimo que fazes.
   5:     Assim em cada lago a lua toda
   6:     Brilha, porque alta vive.
   7: 
   8:         Ricardo Reis, 14-2-1933
   9:         (heterônimo de Fernando Pessoa)
  10: 

A chamada S.rstrip() que devolve uma cópia da string S sem os "caracteres brancos" que ela tiver em seu final. São considerados caracteres brancos os caracteres espaço (' '), tabulação (\t) e quebra de linha (\n).

Temos também as funções lstrip() (que devolve uma cópia da string eliminando todos os caracteres brancos do início da string) e lstrip() (que devolve uma cópia da string eliminando todos os caracteres brancos do início e do fim da string). Veja os exemplos abaixo:

In [10]:
texto = "\n\n  \t  Pequeno texto de teste! \t\t \n\n"
print(texto)
print("--------------")
print(texto.rstrip())
print("--------------")
print(texto.lstrip())
print("--------------")
print(texto.strip())
print("--------------")


  	  Pequeno texto de teste! 		 


--------------


  	  Pequeno texto de teste!
--------------
Pequeno texto de teste! 		 


--------------
Pequeno texto de teste!
--------------

Mas agora, voltando ao problema 26: e se o nome de arquivo digitado pelo usuário não corresponde a um arquivo que existe? Seria interessante avisar o usuário sobre o problema e permitir que ela escolha um outro arquivo. A Solução 4 faz isso.

Solução 4

In [11]:
abriu = False
while not abriu:
    nome_do_arquivo = input("Digite o nome do arquivo de dados: ")
    
    try: 
        arquivo = open(nome_do_arquivo, 'r') 
    except FileNotFoundError:
        print(nome_do_arquivo, " não encontrado. Você digitou direito?")
    else:
        abriu = True

nlin = 1
for linha in arquivo:
    print('%4d: %s' %(nlin,linha), end="")
    nlin += 1
Digite o nome do arquivo de dados: meu_arquivo.txt
meu_arquivo.txt  não encontrado. Você digitou direito?
Digite o nome do arquivo de dados: meu_arquivo_utf8.txt
   1:     Para ser grande, sê inteiro: nada
   2:     Teu exagera ou exclui.
   3:     Sê todo em cada coisa. Põe quanto és
   4:     No mínimo que fazes.
   5:     Assim em cada lago a lua toda
   6:     Brilha, porque alta vive.
   7: 
   8:         Ricardo Reis, 14-2-1933 
   9:         (heterônimo de Fernando Pessoa)	
  10: 

Problema 27

  1. Escreva uma função separa, que recebe um string texto e um caractere separador. A função "corta" o texto nos separadores, retornando uma lista com as palavras do texto.

Exemplo: para o texto: ",1,,2,3," e a vírgula como separador, a saída deve ser a lista:

['', '1', '', '2', '3', '']

onde '' indica uma palavra vazia (entre 2 separadores consecutivos).

In [12]:
def separa(texto, sep):
    lista = []
    palavra = ''
    for l in texto:        
        if l == sep:
            lista.append(palavra)
            palavra = ''
        else:
            palavra += l
    lista.append(palavra)
    return lista 
  1. Escreva um programa que leia uma linha com palavras separadas por vírgula, e determina o comprimento da maior palavra. A linha pode conter palavras vazias.
In [14]:
frase = input("Digite palavras separadas por vírgula: ")
palavras = separa(frase, ',')
print (palavras)

if len(palavras) > 0:
    maxp = palavras[0]
    for p in palavras:
        print ("A palavra '%s' tem %d caracteres."%(p, len(p)))
        if len(p) > len(maxp):
            maxp = p
    print("A maior palavra é '%s', que tem %d caracteres."%(maxp, len(maxp)))
else:
    print("Não achei nenhuma palavra em sua frase!")    
Digite palavras separadas por vírgula: ,testinho,teste,testão,test
['', 'testinho', 'teste', 'testão', 'test']
A palavra '' tem 0 caracteres.
A palavra 'testinho' tem 8 caracteres.
A palavra 'teste' tem 5 caracteres.
A palavra 'testão' tem 6 caracteres.
A palavra 'test' tem 4 caracteres.
A maior palavra é 'testinho', que tem 8 caracteres.

  1. Fazer o mesmo programa usando a função split()
In [15]:
frase = input("Digite palavras separadas por vírgula: ")
palavras = frase.split(',')
print (palavras)

if len(palavras) > 0:
    maxp = palavras[0]
    for p in palavras:
        print ("A palavra '%s' tem %d caracteres."%(p, len(p)))
        if len(p) > len(maxp):
            maxp = p
    print("A maior palavra é '%s', que tem %d caracteres."%(maxp, len(maxp)))
else:
    print("Não achei nenhuma palavra em sua frase!")    
Digite palavras separadas por vírgula: ,testinho,teste,testão,test
['', 'testinho', 'teste', 'testão', 'test']
A palavra '' tem 0 caracteres.
A palavra 'testinho' tem 8 caracteres.
A palavra 'teste' tem 5 caracteres.
A palavra 'testão' tem 6 caracteres.
A palavra 'test' tem 4 caracteres.
A maior palavra é 'testinho', que tem 8 caracteres.

Obs.: Quando fazemos uma chamada do tipo S.split(), ou seja, chamamos a split a partir de uma string S sem passar para a função nenhum separador, a função separará S nos caracteres brancos (espaços, tabulações e quebras de linhas); além disso, as strings vazias são removidas da lista de resultado. Veja os exemplos abaixo:

In [16]:
texto = "Para ser  grande,\t sê inteiro:\tnada\nTeu exagera    ou exclui."
print(texto)
print("----------")
print("Separando pelo caracter de espaço: ", texto.split(" "))
print("Separando pelo caracter de tabulação: ", texto.split("\t"))
print("Separando pelos caracteres brancos: ", texto.split())
Para ser  grande,	 sê inteiro:	nada
Teu exagera    ou exclui.
----------
Separando pelo caracter de espaço:  ['Para', 'ser', '', 'grande,\t', 'sê', 'inteiro:\tnada\nTeu', 'exagera', '', '', '', 'ou', 'exclui.']
Separando pelo caracter de tabulação:  ['Para ser  grande,', ' sê inteiro:', 'nada\nTeu exagera    ou exclui.']
Separando pelos caracteres brancos:  ['Para', 'ser', 'grande,', 'sê', 'inteiro:', 'nada', 'Teu', 'exagera', 'ou', 'exclui.']

Problema 28

Escreva um programa que lê vários números reais em uma mesma linha e imprime a soma.

In [17]:
texto = input("Números: ")

numeros = texto.split()
soma = 0
for n in numeros:
    soma += float(n)

print("Soma = %f" %(soma))
Números: 4.87  37.2 64.9 2.124 95
Soma = 204.094000

Problema 29

Escreva um programa que leia um arquivo contendo ao menos 1 número real por linha, e para cada linha imprima a sua soma. Ao final, o programa deve imprimir também a soma total.

Exemplo: para o arquivo numeros.txt com:

5 4 3 2 1 4 4 4 2.7 3.14 2.1

a saída deve ser:

Digite o nome do arquivo: numeros.txt Soma = 15.000000 Soma = 12.000000 Soma = 2.700000 Soma = 5.240000 Total = 34.940000

In [21]:
import sys

nome = input("Digite o nome do arquivo: ")

try:
    arquivo = open(nome, 'r')   # abre o arquivo para leitura
except IOError:
    print("Não consegui abrir o arquivo %s" %(nome))
    sys.exit(0)                 # Encerra a execução do programa

total = 0
for linha in arquivo:
    numeros = linha.split()
    soma = 0
    for n in numeros:
        soma += float(n)
    print("Soma = %f"%(soma))
    total += soma

print("Total = %f"%(total))

arquivo.close()  # fecha o arquivo 
Digite o nome do arquivo: numeros.txt
Soma = 15.000000
Soma = 12.000000
Soma = 2.700000
Soma = 5.240000
Total = 34.940000

Tópicos vistos na aula 13

Referências e outros materiais para estudo