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:


>>> 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:


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

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:

def le(fich):
f_in = open(fich,'r')
texto = f_in.read()
print 'Todo:\n',texto

f_in.seek(0,0)

texto = f_in.read(7)
print 'Parte:\n',texto

f_in.close()

if __name__ == '__main__':
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?

def le_palavras(fich):
f_in = open(fich,'r')
texto = f_in.read()
lista_palavras = texto.split()
print 'Todas as palavras:\n',lista_palavras

f_in.seek(0,0)
texto = f_in.read().split()
print 'Todas as palavras - Bis:\n',texto

f_in.close()


if __name__ == '__main__':
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.

def le_linha(fich):
f_in = open(fich,'r')
linha = f_in.readline()
print 'Linha a linha:\n'

while linha != '':
print 'Linha: ', linha
linha = f_in.readline()

f_in.seek(0,0)

texto = f_in.read().split('\n')
print 'Linha a linha:\n'
for linha in texto:
print 'Linha: ',linha

f_in.close()


if __name__ == '__main__':
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:

>>>
Evaluating ficheiros.py
Linha a linha:

Linha: Este pequeno texto pode

Linha: ser um exemplo do que

Linha: significa um ficheiro de...

Linha: texto

Linha a linha:

Linha: Este pequeno texto pode
Linha: ser um exemplo do que
Linha: significa um ficheiro de...
Linha: texto
Linha:
>>>

O readline mantém as marcas de fim de linha!!! Como pode alterar a situação? É muito fácil:

def le_linhas(fich):
f_in = open(fich,'r')
linha = f_in.readline()
print 'Linha a linha:\n'

while linha != '':
print 'Linha: ', linha[:-1]
linha = f_in.readline()
f_in.close()

Como se vê retiramos o último caracter à linha que é precisamente o \n! Também podemos ler as linhas aos bocados:

def le_linhas(fich):
f_in = open(fich,'r')
linha = f_in.readline(5)
print 'Todas as linhas:\n'

while linha != '':
print 'Linha: ', linha
linha = f_in.readline(5)
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.

def le_linhas(fich):
f_in = open(fich,'r')
lista_linhas = f_in.readlines()
print 'Todas as linhas:\n', lista_linhas

f_in.seek(0,0)

linha = f_in.readline()
print 'Linha a linha:\n'

while linha != '':
print 'Linha: ', linha
linha = f_in.readline()

f_in.seek(0,0)

texto = f_in.read().split('\n')
print 'Todas as linhas:\n', texto

f_in.close()


if __name__ == '__main__':
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.)

def le_linhas(fich):
f_in = open(fich,'r')
lista_linhas = f_in.readlines(3)
print 'Todas as linhas:\n', lista_linhas
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:

def le_ficheiro(ficheiro):
f_in = open(ficheiro, 'r')
for linha in f_in:
print 'Linha: ', linha
f_in.close()
.

Sem comentários:

Enviar um comentário