Todos os programas que vimos até agora obtêm dados do standard input, por exemplo caracteres introduzidos no teclado durante uma interacção, e enviam dados para o standard output, por exemplo sequência de caracteres mostradas no ecrã. Quando um programa termina, todos os dados utilizados pelo mesmo desaparecem e não os podemos recuperar.
No entanto a maior parte dos programas que utilizamos nos nossos computadores mantêm estado, ou seja, quando voltamos a executá-los podemos continuar onde ficámos numa utilização anterior, e por outro lado podemos fazer uso de várias fontes e destinos de dados. Neste caso diz-se que temos dados persistentes no sentido que estes perduram independentemente da execução do programa, sendo guardados num disco rígido, numa directoria partilhada, num sistema de armazenamento online, etc. Em qualquer caso um destes casos, os dados são em geral armazenados em ficheiros.
Veremos nesta aula como trabalhar com ficheiros.
Um ficheiro tem alguns aspectos particulares:
- podem existir independentemente de qualquer programa;
- durante a execução de um programa, um ficheiro pode estar num de dois estados, em modo de leitura (em que estamos a ler valores do mesmo) ou em modo de escrita (em que estamos a escrever valores no mesmo).
Os ficheiros existem fisicamente num sistema de ficheiros, em geral organizados em directorias. Quando queremos utilizar um ficheiro temos de indicar a sua localização física. É importante notar que a especificação da localização varia, por exemplo, consoante o sistema operativo que estamos a utilizar e/ou se o ficheiro está numa localização local ou remota.
O tipo ficheiro
Dada a localização física do ficheiro em que estamos interessados, e modo como queremos aceder ao mesmo, temos de realizar uma operação de abertura do ficheiro. Em Python recorremos então à função pré-definida open
, com a seguinte sintaxe
open(<expressão>, <modo>{, encoding = <tipo>})
em que os dois primeiros argumentos são obrigatórios e o último é opcional:
- o primeiro argumento é uma
<expressão>
cujo valor corresponde à string que representa a localização do ficheiro, incluindo o seu nome; - o segundo argumento é uma das cadeias de caracteres seguintes
<modo> ::= 'r' | 'w' | 'a'
denotando a abertura para leitura ("read"), escrita ("write") e escrita a partir do final do ficheiro ("append"), respectivamente;
- o terceiro permite-nos indicar o tipo de codificação dos caracteres no ficheiro.
O resultado da operação open
é o valor que corresponde à identidade associada ao ficheiro.
Leitura
Quando abrimos um ficheiro para leitura está subentendido que esse ficheiro existe. Caso o ficheiro não exista, será gerado um erro.
>>> open('nofile.txt', 'r') Traceback (most recent call last): File "<stdin>", line 1, in <module> FileNotFoundError: [Errno 2] No such file or directory: 'nofile.txt' >>>
Vamos assumir que temos o ficheiro teste.txt
na directoria em que estamos a trabalhar, ou seja, na directoria actual, com o seguinte conteúdo:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi quis dui at lectus ornare pulvinar. Curabitur eu lacinia lacus. Morbi ac dui nec magna aliquet sagittis sit amet sed justo. Nulla mattis nisi et orci tincidunt, ac vulputate nisl pretium. Praesent vel orci eget mi pulvinar ullamcorper. Ut eu nibh sit amet leo efficitur laoreet. Nullam non libero euismod dui pretium tempus. Nullam tincidunt suscipit diam, bibendum pharetra felis accumsan ac. Pellentesque pulvinar posuere odio id congue. Integer efficitur velit a tincidunt pellentesque. Cras quis odio euismod, ornare elit at, facilisis libero. Sed semper augue sed fringilla rhoncus. Proin ut leo ante. Nullam ac urna vel orci viverra tempor. Etiam sagittis justo erat, ut tempor orci fringilla quis.
Para abrir o ficheiro podemos fazer o seguinte, assumindo que o ficheiro está codificado em UTF-16,
>>> f = open('teste.txt', 'r', encoding = 'UTF-16') >>> f <_io.TextIOWrapper name='teste.txt' mode='r' encoding='UTF-16'> >>>
Em geral os ficheiros são lidos de forma sequencial e é utilizado internamente (pelo Python no nosso caso) um indicador de leitura que indica o próximo elemento a ser lido. No caso de um ficheiro aberto para leitura, este indicador é inicializado no primeiro elemento do ficheiro e desloca-se a cada leitura para o final do ficheiro.
Uma vez o ficheiro <file>
aberto para leitura, podemos efectuar algumas operações sobre o mesmo:
<file>.readline()
, que lê uma linha do ficheiro e retorna a string correspondente, ou a string vazia''
caso tenhamos chegado ao final do ficheiro;<file>.readlines()
, que lê todas as linhas no ficheiro a partir do indicador de leitura e retorna uma lista com as strings correspondentes às linhas lidas, ou a lista vazia[]
caso tenhamos chegado ao final do ficheiro;<file>.read()
, que lê todos os caracteres do ficheiro a partir do indicador de leitura e retorna uma string com todos os caracteres lidos, ou a string vazia''
se o indicador de leitura estiver já no final do ficheiro;<file>.close()
, que realiza a operação de fecho do ficheiro, desfazendo a associação entre o programa e o ficheiro.
Exemplo:
>>> f = open('teste.txt', 'r') >>> l = f.readline() >>> l 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi quis\n' >>> ll = f.readlines() >>> ll ['dui at lectus ornare pulvinar. Curabitur eu lacinia lacus. Morbi ac\n', 'dui nec magna aliquet sagittis sit amet sed justo. Nulla mattis nisi\n', 'et orci tincidunt, ac vulputate nisl pretium. Praesent vel orci eget mi\n', 'pulvinar ullamcorper. Ut eu nibh sit amet leo efficitur laoreet. Nullam\n', 'non libero euismod dui pretium tempus. Nullam tincidunt suscipit diam,\n', 'bibendum pharetra felis accumsan ac. Pellentesque pulvinar posuere odio\n', 'id congue. Integer efficitur velit a tincidunt pellentesque. Cras quis\n', 'odio euismod, ornare elit at, facilisis libero. Sed semper augue sed\n', 'fringilla rhoncus. Proin ut leo ante. Nullam ac urna vel orci viverra\n', 'tempor. Etiam sagittis justo erat, ut tempor orci fringilla quis.\n'] >>> f.read() '' >>> f.close() >>> f = open('teste.txt', 'r') >>> f.read() 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi quis\ndui at lectus ornare pulvinar. Curabitur eu lacinia lacus. Morbi ac\ndui nec magna aliquet sagittis sit amet sed justo. Nulla mattis nisi\net orci tincidunt, ac vulputate nisl pretium. Praesent vel orci eget mi\npulvinar ullamcorper. Ut eu nibh sit amet leo efficitur laoreet. Nullam\nnon libero euismod dui pretium tempus. Nullam tincidunt suscipit diam,\nbibendum pharetra felis accumsan ac. Pellentesque pulvinar posuere odio\nid congue. Integer efficitur velit a tincidunt pellentesque. Cras quis\nodio euismod, ornare elit at, facilisis libero. Sed semper augue sed\nfringilla rhoncus. Proin ut leo ante. Nullam ac urna vel orci viverra\ntempor. Etiam sagittis justo erat, ut tempor orci fringilla quis.\n' >>> f.read() '' >>> f.seek(0) 0 >>> f.read() 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi quis\ndui at lectus ornare pulvinar. Curabitur eu lacinia lacus. Morbi ac\ndui nec magna aliquet sagittis sit amet sed justo. Nulla mattis nisi\net orci tincidunt, ac vulputate nisl pretium. Praesent vel orci eget mi\npulvinar ullamcorper. Ut eu nibh sit amet leo efficitur laoreet. Nullam\nnon libero euismod dui pretium tempus. Nullam tincidunt suscipit diam,\nbibendum pharetra felis accumsan ac. Pellentesque pulvinar posuere odio\nid congue. Integer efficitur velit a tincidunt pellentesque. Cras quis\nodio euismod, ornare elit at, facilisis libero. Sed semper augue sed\nfringilla rhoncus. Proin ut leo ante. Nullam ac urna vel orci viverra\ntempor. Etiam sagittis justo erat, ut tempor orci fringilla quis.\n' >>> f.close() >>> f.read() Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: I/O operation on closed file.
Como vimos em aulas anteriores, é importante ter em conta as várias codificações possíveis para os caracteres, as diferentes formas de terminar linhas e que podem variar de sistema operativo para sistema operativo, e também a diferentes formas de especificar as localizações dos ficheiros dependendo também do sistema operativo e se são locais ou remotos.
Escrita
Neste caso temos de abrir o ficheiro em modo de escrita, 'w'
ou 'a'
. Se o ficheiro não existir, então é criado. Neste caso temos também um indicador denominado indicador de escrita, que indica a posição a posição onde será escrito o próximo elemento. Quando abrimos o ficheiro em modo 'w'
ou 'a'
o indicador de escrita é colocado no início ou no final do ficheiro, respectivamente. Nota-se que no modo 'w'
o conteúdo do ficheiro é eliminado e perdido.
Uma vez o ficheiro <file>
aberto para escrita, podemos efectuar algumas operações sobre o mesmo:
<file>.write(<cadeia de caracteres>)
, que escreve uma linha no ficheiro a seguir ao indicador de escrita e retorna o número de caracteres escritos com sucesso;<file>.writelines(<sequência>)
, que escreve todas as linhas na sequência (uma lista ou um tuplo, por exemplo) no ficheiro a partir do indicador de escrita e não devolve qualquer valor;<file>.close()
, que realiza a operação de fecho do ficheiro, desfazendo a associação entre o programa e o ficheiro.
Exemplo:
>>> f = open('teste.txt', 'w') >>> f.close() >>> f = open('teste.txt', 'r') >>> f.read() '' >>> f.close() >>> f = open('teste.txt', 'w') >>> f.write('fundamentos de programacao') 26 >>> f.close() >>> f = open('teste.txt', 'r') >>> f.read() 'fundamentos de programacao' >>> f.close() >>> f = open('teste.txt', 'a') >>> f.write('\n2015/16\n1o semestre\n') 21 >>> f.close() >>> f = open('teste.txt', 'r') >>> f.read() 'fundamentos de programacao\n2015/16\n1o semestre\n' >>> f.seek(0) 0 >>> ll = f.readlines() >>> f.close() >>> f = open('teste.txt', 'a') >>> f.writelines(ll) >>> f.writelines(ll) >>> f.close() >>> f = open('teste.txt', 'r') >>> f.read() 'fundamentos de programacao\n2015/16\n1o semestre\nfundamentos de programacao\n2015/16\n1o semestre\nfundamentos de programacao\n2015/16\n1o semestre\n' >>> f.seek(0) 0 >>> print(f.read()) fundamentos de programacao 2015/16 1o semestre fundamentos de programacao 2015/16 1o semestre fundamentos de programacao 2015/16 1o semestre >>> f.close() >>>
Depois de aberto um ficheiro para escrita, podemos também utilizar a função print
cuja sintaxe é na realidade definida como se segue:
<escrita de dados> ::= print() | print(file = <nome de ficheiro>) | print(<expressões>) | print(<expressões>, file = <nome de ficheiro>) <nome de ficheiro> ::= <nome>
Exemplo:
>>> f = open('teste.txt', 'w') >>> f.write('fundamentos de programacao\n') 27 >>> print(2015, '/', 2016, file = f) >>> f.close() >>> f = open('teste.txt', 'r') >>> print(f.read()) fundamentos de programacao 2015 / 2016 >>> f.close() >>>
Notar que nesta aula considerámos apenas ficheiros de texto.