quinta-feira, 21 de janeiro de 2010

Equívocos III

Sabemos que os ficheiros de texto são uma longa cadeia de caracteres com características especiais. O seu conteúdo está armazenado de modo permanente num disco externo. Para aceder ao seu conteúdo o ficheiro tem que ser primeiro aberto. O que acontece quando fazemos:

1.>>> f_in = open(‘/tempo/data/ficheiro.txt’,’r’)

O que acontece é semelhante ao que se passa quando fazemos, por exemplo, a= 5. Aqui, associamos o nome a ao objecto 5. No caso da instrução acima, associamos o nome f_in a um objecto do tipo ficheiro:

1.>>> f_in = open('/tempo/data/ficheiro.txt')
2.>>> f_in
3.<open file '/tempo/data/ficheiro.txt', mode 'r' at 0xe02c50>
4.>>>

Podemos agora, através do nome f_in aceder ao conteúdo do ficheiro. O acesso é por norma sequencial, existindo uma marca para a posição (o caracter) que pode ser acedido. Essa marca pode ser manipulada pela operação seek.

Existem três comandos fundamentais de leitura: read, readline, readlines. No primeiro caso lemos o conteúdo de todo o ficheiro a partir da marca, no segundo, lemos a próxima linha a partir da marca, no terceiro, lemos todas as linhas partir da marca.

Vejamos o uso de read:
01.def le(fich):
02.    f_in = open(fich,'r')
03.    texto = f_in.read()
04.    print 'Todo:\n',texto
05.     
06.    f_in.seek(0,0)
07. 
08.    texto = f_in.read(7)
09.    print 'Parte:\n',texto
10.     
11.    f_in.close()
12.         
13.if __name__ == '__main__':
14.    le('/tempo/data/ficheiro.txt')

Notar que podemos ler apenas n caracteres. Notar ainda que o ficheiro fica agora guardado como uma cadeia de caracteres e associado ao nome texto. Finalmente, esteja atento ao modo como voltamos ao início do ficheiro com a operação seek. Mas admitamos que queríamos manipular o ficheiro palavra a palavra. Como proceder?
01.def le_palavras(fich):
02.    f_in = open(fich,'r')
03.    texto = f_in.read()
04.    lista_palavras = texto.split()
05.    print 'Todas as palavras:\n',lista_palavras
06.     
07.    f_in.seek(0,0)
08.    texto = f_in.read().split()
09.    print 'Todas as palavras - Bis:\n',texto
10.     
11.    f_in.close()
12.     
13.     
14.if __name__ == '__main__':
15.    le_palavras('/tempo/data/ficheiro.txt')

Veja-se como podemos fazer de duas maneiras diferentes. Percebe porque é o mesmo? Note-se ainda que passamos a ter uma lista de cadeias de caracteres.

Passemos agora à leitura por linhas.
01.def le_linha(fich):
02.    f_in = open(fich,'r')
03.    linha = f_in.readline()
04.    print 'Linha a linha:\n'
05. 
06.    while linha != '':
07.        print 'Linha: ', linha
08.        linha = f_in.readline()
09.  
10.    f_in.seek(0,0)
11.     
12.    texto = f_in.read().split('\n')
13.    print 'Linha a linha:\n'
14.    for linha in texto:
15.        print 'Linha: ',linha
16. 
17.    f_in.close()
18.     
19. 
20.if __name__ == '__main__':
21.    le_linha('/tempo/data/ficheiro.txt')

No programa apresentado vemos duas maneiras de fazer o processamento do conteúdo do ficheiro linha a linha. Se executar o código verá que existe uma diferença subtil entre usar o readline e a associação read-split. Veja bem:
01.>>>
02.Evaluating ficheiros.py
03.Linha a linha:
04. 
05.Linha:  Este pequeno texto pode
06. 
07.Linha:  ser um exemplo do que
08. 
09.Linha:  significa um ficheiro de...
10. 
11.Linha:  texto
12. 
13.Linha a linha:
14. 
15.Linha:  Este pequeno texto pode
16.Linha:  ser um exemplo do que
17.Linha:  significa um ficheiro de...
18.Linha:  texto
19.Linha: 
20.>>>

O readline mantém as marcas de fim de linha!!! Como pode alterar a situação? É muito fácil:
01.def le_linhas(fich):
02.    f_in = open(fich,'r')
03.    linha = f_in.readline()
04.    print 'Linha a linha:\n'
05. 
06.    while linha != '':
07.        print 'Linha: ', linha[:-1]
08.        linha = f_in.readline()
09.    f_in.close()

Como se vê retiramos o último caracter à linha que é precisamente o \n! Também podemos ler as linhas aos bocados:
01.def le_linhas(fich):
02.    f_in = open(fich,'r')
03.    linha = f_in.readline(5)
04.    print 'Todas as linhas:\n'
05. 
06.    while linha != '':
07.        print 'Linha: ', linha
08.        linha = f_in.readline(5)
09.   f_in.close()

Neste caso em vez de ler a linha toda de uma vez, ela vai ser lida considerando, no exemplo apresentado, 5 caracteres de cada vez. Experimente!

Passemos à última situação. Vamos ler todas as linhas de uma vez, usando readlines. O resultado é uma lista de cadeias de caracteres, em que cada elemento da lista é uma linha.
01.def le_linhas(fich):
02.    f_in = open(fich,'r')
03.    lista_linhas = f_in.readlines()
04.    print 'Todas as linhas:\n', lista_linhas
05. 
06.    f_in.seek(0,0)
07.     
08.    linha = f_in.readline()
09.    print 'Linha a linha:\n'
10. 
11.    while linha != '':
12.        print 'Linha: ', linha
13.        linha = f_in.readline()
14.  
15.    f_in.seek(0,0)
16.     
17.    texto = f_in.read().split('\n')
18.    print 'Todas as linhas:\n', texto
19. 
20.    f_in.close()
21. 
22.         
23.if __name__ == '__main__':
24.    le_linhas('/tempo/data/ficheiro.txt')

Notar que é conservado o caracter fim de linha. Para comparação apresentamos como se podia fazer recorrendo ao readline e ao read. Veja as diferenças!

Para concluir. Também neste caso podemos limitar o número de linhas a ler (no exemplo abaixo, serão 3 as linhas.)
1.def le_linhas(fich):
2.    f_in = open(fich,'r')
3.    lista_linhas = f_in.readlines(3)
4.    print 'Todas as linhas:\n', lista_linhas
5.    f_in.close()

Em conclusão, apenas dizer que o comando a usar depende do problema. Queremos manipular caracteres, palavras ou linhas? Não esquecer também do detalhe do sinal de fim de ficheiro.

Oops! Já quase que me esquecia. Sempre que tiver que manipular todo um ficheiro, linha a linha, pode também usar esta construção, simples e clara:
1.def le_ficheiro(ficheiro):
2.    f_in = open(ficheiro, 'r')
3.    for linha in f_in:
4.        print 'Linha: ', linha
5.    f_in.close()
.

Sem comentários:

Enviar um comentário