Definição
Formas de armazenamento e recuperação de dados em arquivos e diretórios, utilizando a linguagem de programação Python.
PROPÓSITO
Compreender os passos necessários para manipulação de arquivos e strings, utilizando boas práticas e tratamento de exceção, para garantir o correto funcionamento do programa.
Recomendação
Antes de iniciar o conteúdo deste tema, sugerimos que tenha o software Python 3.7 instalado em seu computador. Ele será utilizado nos módulos deste tema.
Você pode pesquisar e baixar o Python 3.7 no site oficial do Python.
Para programar os exemplos apresentados neste módulo, utilizamos a IDE Pycharm Community. Você pode baixar essa IDE gratuitamente no site oficial da JetBrains.
Baixe os códigos fonte Python, deste tema, para lhe auxiliar na realização das atividades.
OBJETIVOS
Módulo 1
Identificar as funções de manipulação de arquivos
Módulo 2
Reconhecer as funções de manipulação de strings
Módulo 3
Descrever as exceções na manipulação de arquivos e outras operações
INTRODUÇÃO
Uma das razões pela qual o Python se popularizou foi a facilidade de programar utilizando essa linguagem.
A manipulação de arquivos em Python não é diferente. Os criadores se preocuparam em disponibilizar aos desenvolvedores o que realmente importa!
Com nome de métodos intuitivos, como read (ler) e write (escrever), e tratamentos de exceções específica para cada problema, o Python disponibiliza uma simples e poderosa forma de trabalhar com arquivos.
Neste tema, veremos como manipulá-los de forma correta, garantido que o programa rode sem problemas.
É muito comum ajustarmos e prepararmos um texto antes de incluí-lo em um arquivo. Ajustes como remover espaço em branco, colocar todas as letras maiúsculas, substituir palavras e adicionar conteúdo de variável são alguns exemplos.
Esses ajustes podem ser realizados a partir de métodos de manipulação de strings, que também serão tratados neste tema.
MÓDULO 1
Identificar as funções de manipulação de arquivos
Conceitos
Abrindo um arquivo
Neste módulo, veremos as operações básicas de manipulação de arquivos:
- Abrir.
- Fechar.
- Ler.
- Escrever.
A primeira operação que precisamos realizar, independentemente se vamos ler o conteúdo de um arquivo ou adicionar um conteúdo, é abrir o arquivo.
Para abrir um arquivo, o Python disponibiliza a função interna chamada open. Essa função está disponível globalmente, ou seja, não é preciso importá-la.
A função open retorna um objeto do tipo arquivo. Sua forma mais simples de utilização tem a seguinte sintaxe:
arquivo = open (caminho)
Utilizamos a função open com o parâmetro caminho. Esse parâmetro é
uma string que representa a localização do arquivo no sistema de arquivos.
No exemplo a seguir, vemos como é fácil abrir um arquivo.
Nesse exemplo, o caminho utilizado para abrir o arquivo foi “teste.txt”, pois o script e o arquivo que abrimos estão no mesmo diretório.
Porém, não precisamos nos limitar a manter os arquivos e scripts no mesmo diretório.
Veja como o Python trata o acesso aos arquivos a seguir.
O caminho de um arquivo pode ser classificado em dois tipos:
Caminho absoluto
Caminho absoluto é a referência completa para se encontrar um arquivo ou diretório. Ele deve começar com uma barra ( / ) ou o rótulo do drive ( C:, D: ...).
Exemplo:
- open(“C:\Downloads\arquivo.txt”) – utilizado em ambientes MS Windows.
- open(“/home/usuario/arquivo.txt”) – utilizado em ambientes Linux.
Caminho relativo
Caminho relativo é a referência para se encontrar um arquivo ou diretório a partir de outro diretório. Normalmente, a partir do diretório de onde o script está.
Exemplo:
- open(“arquivo.txt”), para os casos em que o arquivo está no mesmo diretório do script.
- open(“../arquivo.txt”), para os casos em que o arquivo está no diretório acima do script.
A seguir, vamos criar um script que ilustra as diferentes formas de referenciar um arquivo com caminhos absolutos e relativos.
Neste exemplo, alteramos um pouco a forma de exibir o conteúdo.
O Python também disponibiliza algumas funções para exibir os caminhos absolutos e relativos de um arquivo ou diretório.
- Na linha 11, utilizamos a função path.relpath para imprimir o caminho relativo do arquivo1, a partir do nome do arquivo passado como parâmetro.
- Na linha 12, utilizamos a função path.abspath para exibir o caminho absoluto do mesmo arquivo.
Observe que, mesmo utilizando o caminho relativo para abrir o arquivo (linha 4), é possível obter o caminho absoluto utilizando a função abspath. Isso pode ser verificado na saída do console.
- Na linha 14, utilizamos a função interna print para imprimir a variável arquivo1. Verifique, na saída do console, onde foi impressa a representação do objeto arquivo1:
Neste módulo, vamos tratar apenas de arquivos do tipo texto, ou seja, objetos TextIOWrapper. A seguir, vamos apresentar os diferentes modos de acesso aos arquivos.
<_io.TextIOWrapper name='dados1.txt' mode='r' encoding='cp1252'>
Desmembrando essa saída, temos: o tipo do objeto, TextIOWrapper, que trata de arquivos de texto; o nome do arquivo, name='dados.txt'; o modo de acesso ao arquivo, mode='r'; e a codificação do arquivo, encoding='cp1252'.]
Modos de acesso a um arquivo
Quando abrimos um arquivo, precisamos informar ao Python o que desejamos fazer, ou seja, qual será o modo (mode) de acesso ao arquivo. O modo é um dos parâmetros da função open, e cada modo é representado por uma string.
Os principais modos são:
r: leitura (read)
w: escrita (write)
a: acrescentar (append)
O modo padrão da função open é o modo leitura (“r”).
Esses modos podem ser combinados. Para informar que desejamos ler e escrever em um arquivo, utilizamos a string “r+”, por exemplo.
O Python também nos permite diferenciar arquivos texto de arquivos binários, como uma imagem, por exemplo. Para informar que desejamos abrir um arquivo binário, adicionamos a string “b” ao modo, ficando “rb”, “wb” e “ab”.
A tabela a seguir resume os modos de acesso a arquivos.
Caractere |
Significado |
---|---|
'r' |
Abre o arquivo para leitura (default). |
'w' |
Abre o arquivo para escrita, truncando o arquivo primeiro. |
'x' |
Cria um arquivo para escrita e falha, caso ele exista. |
'a' |
Abre o arquivo para escrita, acrescentando conteúdo ao final do arquivo, caso ele exista. |
'b' |
Modo binário. |
't' |
Modo texto (default). |
'+' |
Abre o arquivo para atualização (leitura ou escrita). |
Atributos de um arquivo
O objeto do tipo arquivo contém alguns atributos importantes, como name, mode e closed, expostos no script a seguir.
Lendo o conteúdo de um arquivo
Agora que já sabemos abrir e fechar um arquivo, vamos ver as formas de ler seu conteúdo.
O Python disponibiliza três métodos para leitura do conteúdo de um arquivo-texto:
read()
Retorna todo o conteúdo de um arquivo como uma única string.
readline()
Retorna uma linha de um arquivo, incluindo os caracteres de final de linha (\n ou \r\n), e avança o cursor para a próxima linha.
readlines()
Retorna uma lista onde cada item da lista é uma linha do arquivo.
Na imagem a seguir, Figura 5, temos três scripts, em que cada um utiliza um dos métodos descritos anteriormente para leitura do arquivo.
Três scripts
Em cada um dos scripts, vamos abrir o mesmo arquivo dados.txt dos exemplos anteriores, ler o conteúdo, verificar o tipo de conteúdo retornado por cada método de leitura e imprimir o valor canônico (real) do conteúdo lido.
Observe que explicitamos o modo de operação como leitura (“r”).
- No script5.py, seguimos os mesmos passos do script anterior, porém, na linha 3, utilizamos o método readline().
- Na linha 5, verificamos que o tipo do conteúdo retornado pelo método readline() também é um objeto do tipo str (string).
- Na linha 8, imprimimos a representação do conteúdo que contém apenas a primeira linha do arquivo dados.txt (incluindo o caractere de final de linha \n). Isso aconteceu porque, quando abrimos o arquivo utilizando o modo leitura (‘r’), o cursor interno de leitura fica posicionado no início do arquivo.
- Se chamarmos novamente o método readline(), linha 10, será retornado à próxima linha do arquivo, que foi impressa na linha 13. Confira a saída do script 5 no console abaixo dele.
No script6.py, seguimos novamente os mesmos passos, mas, desta vez, utilizamos o método readlines().
- Na linha 5, verificamos que o tipo do conteúdo retornado pelo método readlines() é um objeto do tipo list (lista).
- Na linha 8, imprimimos o conteúdo retornado, que é uma lista onde cada item da lista é uma linha do arquivo. Veja a saída desse script no console abaixo dele.
Além dos três métodos apresentados anteriormente, os objetos do tipo arquivo são iteráveis. Com isso, podemos utilizar o laço for diretamente sobre os objetos desse tipo.
No exemplo ao lado, vamos mostrar como iterar diretamente sobre um arquivo.
- Na linha 1, abrimos o arquivo da mesma maneira que fizemos nos exemplos anteriores.
- Na linha 4, utilizamos o laço for para iterar diretamente sobre a variável arquivo. Para cada iteração, recebemos uma nova linha do arquivo, disponibilizada na variável linha, impressa na linha 5. Observe a saída do console abaixo da figura.
Dica
1 - Quando precisamos abrir um arquivo muito grande, é inviável utilizar os métodos read e readlines, pois eles retornam todo o conteúdo do arquivo de uma só vez, seja na forma de string, seja na forma de lista. Isso pode consumir todos os recursos do computador, travando seu programa.
Nesses casos, precisamos chamar o método readline inúmeras vezes até o final do arquivo ou iterar diretamente sobre o objeto do tipo arquivo.
2 - Após utilizar qualquer um dos métodos para leitura do arquivo apresentados anteriormente, não podemos utilizá-los novamente. Isso acontece porque o cursor estará posicionado ao final do arquivo, e as chamadas aos métodos read, readline ou readlines retornarão vazias.
Para situações em que precisamos ler o conteúdo de um arquivo mais de uma vez, temos duas opções. Na sua opinião, quais são elas?
- Fechar e abrir novamente o arquivo.
- Utilizar o método seek(n), passando como argumento o número da linha onde desejamos posicionar o cursor. A chamada seek(0) retorna o cursor para o início do arquivo.
Depois de conhecer a resposta correta, confira, a seguir, o exemplo do script8, onde exploramos na prática essa situação.
Abrimos o arquivo em modo leitura.
Lemos todo seu conteúdo utilizando o método read, que é impresso na linha 5. Veja no console à direita da imagem.
Utilizamos o método read para ler novamente o conteúdo do arquivo e atribuímos o valor retornado à variável conteudo_releitura. Na linha 9, imprimimos o conteúdo dessa variável, que, conforme exibido no console, é uma string vazia ('').
Para contornar esse problema, fechamos e abrimos o arquivo novamente, linhas 11 e 14, respectivamente. Na linha 16, utilizamos novamente o método read e imprimimos o conteúdo retornado na linha 18. Observe que, mais uma vez, conseguimos acessar todo o conteúdo do arquivo.
Para demonstrar a utilização do método seek, no mesmo arquivo que já estava aberto, arquivo_reaberto, utilizamos o método seek(0), linha 20. Imprimimos mais uma vez o conteúdo correto do arquivo na linha 23.
Toda a sequência pode ser acompanhada pelo console.
Todos os três métodos apresentados anteriormente aceitam como parâmetro a quantidade de bytes que desejamos ler.
O valor padrão para esse parâmetro é -1, o que corresponde a todo o arquivo.
Escrevendo conteúdo em um arquivo
Nesta seção, vamos mostrar como, a partir da função open, escrever conteúdo em um arquivo.
A primeira modificação é alterar o modo de acesso ao arquivo. Para escrita de texto, podemos utilizar o modo w (write) ou o modo a (append):
- O modo w abre o arquivo para escrita, truncando o arquivo em primeiro lugar. Caso ele não exista, será criado um.
- O modo a abre o arquivo para escrita, acrescentando conteúdo ao final dele, caso ele exista. Caso contrário, será criado um arquivo.
O Python disponibiliza dois métodos para escrita de conteúdo em um arquivo texto, para o modo w e para o modo a. Os métodos write e writelines são descritos a seguir:
Escreve todo o conteúdo passado como parâmetro no arquivo.
Escreve cada item do iterável (exemplo: lista) no arquivo.
No exemplo a seguir, vamos criar dois scripts para mostrar o uso do modo w. No primeiro, script9, vamos utilizar o método write. No segundo, script10, vamos utilizar o método writelines.
Dica
1 - Fique atento, pois o Python não insere quebra de linha (‘\n’) entre os elementos da lista. Precisamos fazer isso manualmente!
2 - Como o modo w trunca o arquivo, ou seja, remove todo o conteúdo do arquivo, caso ele exista, podemos executar esses scripts repetidas vezes e, ainda assim, o resultado será sempre o mesmo.
No próximo exemplo, vamos mostrar como utilizar o modo append (a) para adicionar conteúdo a um arquivo já existente.
Para isso, vamos abrir o arquivo dados_write.txt, criado pelo script9, utilizando o modo a. Utilizamos esse modo para acrescentar conteúdo a um arquivo. Confira, a seguir, o script11.
Boas Práticas
Uma boa prática ao lidar com arquivos é utilizar a palavra reservada with, disponibilizada pelo Python. Ela garante que o arquivo será fechado adequadamente após utilizarmos o arquivo, não sendo necessário chamar o método close explicitamente.
A sintaxe de utilização do with é:
with open(caminho, modo) as nome: (seu código indentado)
Iniciamos com a palavra reservada with, seguida da função open, a palavra reservada as, um nome de variável que receberá o objeto do tipo arquivo e dois pontos. Todo o código indentado posteriormente está dentro do contexto do with, no qual o arquivo referenciado pela variável nome estará disponível.
Veja como utilizar o with no exemplo a seguir. Clique nas setas e acompanhe.
Vídeo com Avaliação
Assista ao vídeo e veja como acontece a manipulação de arquivos no Python.
Para acompanhar o vídeo e poder executar o programa, baixe os arquivos neste link
Verificando o aprendizado
ATENÇÃO!
Para desbloquear o próximo módulo, é necessário que você responda corretamente a uma das seguintes questões:
O conteúdo ainda não acabou.
Clique aqui e retorne para saber como desbloquear.
MÓDULO 2
Reconhecer as funções de manipulação de strings
Conceitos
Métodos de manipulação de strings
Durante a vida de programador, é muito comum nos depararmos com situações em que precisamos realizar alguns ajustes e operações sobre os textos lidos de arquivos.
Ajustes como remover espaço em branco, colocar todas as letras maiúsculas, substituir e contar palavras são alguns exemplos.
Neste módulo, veremos alguns métodos presentes nos objetos do tipo str (string), que são muito utilizados em conjunto com a manipulação de arquivos.
Método strip
Como mostrado nos scripts da figura 5 (script5), ao ler o conteúdo do arquivo, o Python retorna os caracteres de final de linha (\r e \n). Muitas vezes, essa informação não é necessária, principalmente se estivermos tratando uma linha de cada vez.
Dependendo do objetivo, esses caracteres são considerados lixo e podem atrapalhar o processamento que desejamos realizar. Para remover esses caracteres e também espaços em branco adicionais, o tipo str disponibiliza o método strip(). Este método remove esses caracteres do início e do final da linha.
Observe o uso deste método no exemplo a seguir. Clique nas setas para acompanhar cada ação.
Um exemplo real de utilização do strip é quando desejamos contar a quantidade de linhas com algum conteúdo em um arquivo. Dependendo do tamanho do arquivo, é inviável remover manualmente as linhas em branco. Para resolver esses problemas, podemos utilizar o método strip, como mostrado a seguir.
Neste exemplo, vamos abrir o mesmo arquivo do exemplo anterior, dados13.txt, e iterar sobre cada linha, incrementando um contador, que será impresso no final.
Métodos count e split
Outra atividade muito comum na manipulação de arquivos é a contagem do número de vezes que determinada palavra aparece. O Python disponibiliza o método count para strings, que recebe como parâmetro a palavra que desejamos contar e retorna o total de ocorrências dela. Sua sintaxe é a seguinte:
contagem = variavel_string.count(palavra)
Nela, a variavel_string é uma variável do tipo str e palavra é a string que desejamos contar.
Veja, no exemplo a seguir, como utilizamos o método count para contar a quantidade de vezes em que aparece a palavra “Olá”, no arquivo dados13.txt.
Apesar de ser muito simples a utilização do método count do tipo str, pode gerar alguns efeitos indesejáveis, pois esse método também conta as palavras que contêm parte da string passada como argumento.
Exemplo
Considere a frase “Eu amo comer amoras no café da manhã.”. Se utilizarmos o método count, com a string “amo” como argumento, o retorno será 2, pois o método irá considerar tanto a palavra amo quanto a palavra amoras.
Para contornar esse problema, podemos “quebrar” uma frase em palavras e depois verificar se cada palavra é igual à string que buscamos.
Isso nos leva a outro método muito utilizado em processamento de textos, o método split(), que é usado para quebrar uma string em partes menores, retornando uma lista com essas partes. Sua sintaxe é a seguinte:
lista_termos = variavel_string.split(separador)
No exemplo, a variavel_string é uma variável do tipo str, e separador é uma string que desejamos utilizar como ponto de quebra do texto. O retorno desse método é uma lista de strings.
Digamos que desejamos usar o método split com separador ‘–‘ na frase: “Amo futebol – Gosto de basquete”.
O resultado seria uma lista onde o primeiro elemento é a string “Amo futebol ” e o segundo elemento é string “ Gosto de basquete”.
Caso nenhum separador seja passado como argumento, o Python irá utilizar um ou mais espaços como separador padrão.
Dica
A string utilizada como separador não aparecerá em nenhum elemento da lista retornada.
Confira, no exemplo a seguir, em que o método split é utilizado em três frases diferentes para mostrar o comportamento deste método.
Agora que sabemos como funciona o método split, no próximo exemplo, vamos utilizar esse método para realizar a contagem da palavra “amo” na frase do exemplo anterior: “Eu amo comer amoras no café da manhã.”. Vamos aproveitar para comparar os resultados obtidos pelos métodos count e split.
Dica
Para evitar iterar sobre a lista, criar contador e realizar comparações, podemos utilizar o método count da lista, que obteremos o mesmo resultado. Confira o código na imagem.
Após definida a frase, linha 1, e quebrada em palavras com o método split, linha 3, utilizamos o método count da lista lista_termos para contar a ocorrência da string ‘amo’. Observe que o resultado também está correto.
Método join
Assim como há a necessidade de quebrar uma frase em uma lista de palavras, podem existir situações em que ocorra o inverso, ou seja, temos uma lista de palavras ou frases e desejamos concatená-las em uma única string.
Para essa operação, utilizamos o método join do tipo str, que retorna uma única string com todos os elementos da lista concatenados, utilizando determinado conector. Sua sintaxe é a seguinte:
string_final = “conector”.join(iteravel)
Onde ‘conector’ é a string que será utilizada entre os elementos da lista que serão concatenados (ex. ‘, ‘) e iteravel é um iterável, como uma lista ou tupla.
No exemplo a seguir, vamos unir os elementos de uma lista utilizando dois conectores diferentes: o conector vírgula (‘, ‘) e o conector de nova linha (‘\n’). Após a união, vamos gravar o conteúdo em um arquivo para mostrar o resultado.
Observe que o Python foi esperto o suficiente para não adicionar o conector ao último elemento. Isso pode ser percebido pelo resultado do arquivo texto1.txt.
Manipulação de variáveis em strings
Até o momento, realizamos operações sobre strings pré-existentes. No entanto, é muito comum precisarmos juntar valores de variáveis com strings.
Agora, veremos algumas funções relacionadas às strings, começando pela formatação de strings (string formatting).
A formatação de strings permite ajustar como uma string será exibida ou gravada em um arquivo, por exemplo. Ajustes como: número de casas decimais em float, exibição de datas, inclusão de variáveis e espaçamento são alguns dos exemplos.
Existem basicamente três formas de realizar a formatação de strings. São elas:
- Utilizando f-strings (formatted string literals).
- Utilizando o método format() das strings.
- Fazendo manualmente.
Veremos como utilizar f-strings, recurso adicionado na versão 3.6 do Python.
f-strings
Os f-strings são tipos especiais de strings que aceitam uma notação especial para permitir a inclusão de expressões diretamente na string.
F-strings
O objetivo principal da criação das f-strings foi facilitar a formatação de strings.
Para definimos uma variável f-string, precisamos incluir, antes das aspas que definem uma string, a letra f (ou F), como, por exemplo:
minha_string = f”Olá Mundo {expr}”
Dentro das f-string, podemos utilizar expressões em Python entre as chaves, delimitadas pelos caracteres { e }.
Essas expressões incluem variáveis ou literais. Inclusive, podemos fazer chamada para funções ou utilizar métodos de variáveis dentro desses delimitadores.
Todo o conteúdo entre os caracteres { e } é substituído pelo resultado da expressão e interpolados à string.
No exemplo a seguir, vamos comparar a manipulação manual de strings com a utilização de f-string. Também vamos mostrar alguns exemplos de uso de literais mais sofisticados dentro de f-strings.
literais
Literal é algo que o interpretador reconhece como uma sintaxe válida (exemplo: 2 > 3 retorna False, [1, 2]) retorna uma lista.
No próximo exemplo, vamos mostrar algumas funcionalidades adicionais de formatação de string utilizando f-string, como a definição de largura de uma string, formatação de float e de datas.
Para facilitar o entendimento, o script21 foi dividido em três trechos. O primeiro trecho, entre as linhas 3 e 6, trata da formatação de largura do conteúdo de expressões, que serve, principalmente, para alinhar conteúdo de texto. No segundo trecho, das linhas 10 a 16, mostramos como formatar floats. No terceiro trecho, das linhas 20 a 24, mostramos como formatar datas. Clique a seguir para conhecer cada trecho citado.
No primeiro trecho, definimos uma lista chamada frutas na linha 3 e, na linha 4, percorremos cada item dessa lista.
Para cada item, montamos a f-string minha_fruta, que contém o nome da fruta e o número de letras que a fruta tem. Destacamos essa linha a seguir:
Para indicar a largura, ou melhor, o número de espaços que o conteúdo de uma variável deve ocupar, devemos utilizar a sintaxe {variavel:n}, onde temos o nome da variável, seguida de dois pontos (:) e o número de espaços (n) que se deve ocupar.
Caso o tamanho do conteúdo da variável seja menor que o número n, serão incluídos espaços em branco até completar esse tamanho. A posição dos espaços adicionados depende do tipo da variável. Para variáveis do tipo string, os espaços são adicionados à direita, enquanto para variáveis do tipo inteiro, os espaços são adicionados à esquerda.
Caso o tamanho do conteúdo da variável seja maior que o número n, a formatação será ignorada.
Retornando ao exemplo, desejamos imprimir o nome da fruta de forma que ela ocupe 12 espaços ({fruta:12}), e o número de letras da fruta deve ocupar apenas três espaços ({len(fruta):3}). Observe o resultado obtido no console à direita.
No segundo trecho, definimos uma variável float na linha 10 e criamos três f-strings para exibir esse conteúdo.
A formatação com f-string nos permite um controle maior de como será exibido um número do tipo float, no qual podemos definir a largura e o número de casas decimais que devem ser exibidos. A sintaxe para formatar um float é a seguinte:
{variavel_float:largura.precisao f}
Pelo exemplo, temos o nome da variável do tipo float seguida de dois pontos (:), a largura total que o número deve ocupar, incluindo as casas decimais, e o ponto (separador de decimal), seguido de um ponto (.), o número de casas decimais (precisao) e a letra “f”, que deve estar junto à precisão. A largura é opcional.
Na primeira f-string, na linha 11, utilizamos a expressão {pi:.1f}, ou seja, queremos que seja exibido o valor da variável pi com uma casa decimal apenas. Como não especificamos a largura, ela será calculada de forma a acomodar toda a parte inteira do float.
Na f-string da linha 12, utilizamos a expressão {pi:6.1f}, que indica que o número deve ocupar seis espaços, sendo que, necessariamente, deve ter uma casa decimal.
Na última f-string, linha 13, utilizamos a expressão {pi:.4f}, para que seja exibido o número com quatro casas decimais.
Observe, no console, como ficaram os resultados.
No terceiro e último trecho, vamos mostrar como formatar datas em expressões f-string.
Na linha 20, definimos a variável data com a data atual, utilizando o método datetime.now().
Na linha 21, criamos uma f-string para exibir o valor da variável data sem informar ao Python qual formatação ele deve utilizar ({data}). Com isso, a data foi impressa no formato padrão: 2020-08-13 10:50:32.262037.
Na linha 22, utilizamos a expressão {data:%d/%m/%Y}, que indica que desejamos exibir a data no formato “dia/mês/ano” (13/08/2020). Veja o resultado no console à direta.
Dica
O Python disponibiliza outras maneiras de formatar datas. Pesquise mais sobre o módulo datetime na documentação oficial para descobrir outras.
Vídeo com Avaliação
Assista, no vídeo, a manipulação de strings com Python.
Para acompanhar o vídeo e poder executar o programa, baixe os arquivos neste link
Verificando o aprendizado
ATENÇÃO!
Para desbloquear o próximo módulo, é necessário que você responda corretamente a uma das seguintes questões:
O conteúdo ainda não acabou.
Clique aqui e retorne para saber como desbloquear.
MÓDULO 3
Descrever as exceções na manipulação de arquivos e outras operações
Conceitos
Tratamento de exceções
Quando trabalhamos com arquivos, é comum encontrarmos alguns problemas, como arquivo inexistente e falta de permissão para escrever em um arquivo. A maioria desses problemas só pode ser detectada durante a execução do programa.
Quando uma falha inesperada ocorre e o interpretador não consegue resolver o problema, dizemos que houve uma exceção.
Nesses casos, precisamos informar ao interpretador como tratar a exceção, para que o programa não seja interrompido.
Exceção.
A exceção é um evento que ocorre quando o programa se desvia do fluxo normal de execução
Porém, se a exceção é um problema inesperado, como tratá-la?
Ao desenvolver um programa, precisamos procurar na documentação da biblioteca, do módulo ou da própria linguagem de programação se as funcionalidades que vamos utilizar têm exceções mapeadas. Essas exceções são problemas que podem ocorrer, e é nossa tarefa tratá-las.
Você deve estar se perguntando: “O que seria ‘tratar uma exceção’?”. Tratar uma exceção nada mais é do que dizer ao Python o que fazer, ou quais instruções executar, quando ele encontrar um problema.
Para ilustrar, observe o fluxo a seguir.
Quando abrimos um arquivo em modo leitura e esse arquivo não existe, o Python lança uma exceção do tipo FileNotFoundError.
Se não avisarmos ao Python o que fazer quando isso ocorrer, o programa será interrompido.
Nesse caso, um tratamento para essa exceção poderia ser: exibir um pop-up ao usuário informando que o arquivo não existe.
No exemplo a seguir, vamos mostrar o que acontece quando uma exceção lançada não é tratada.
Para resolver isso, precisamos tratar a exceção, ou melhor, uma possível exceção. Esse tratamento informa ao Python uma rota alternativa, caso ele encontre um problema.
Para tratar exceções, precisamos “envolver” o trecho de código passível de erro com a cláusula try/except ou try/except/finally. Veremos apenas a cláusula try/except.
Veja a sintaxe ao lado:
O código crítico que desejamos executar deve estar no escopo do try, enquanto o código alternativo, que será executado em caso de erro, deve estar no escopo do except.
Uma mesma operação pode lançar mais de um tipo diferente de exceção, em que, para cada tipo, Erro1 e Erro2, devemos ter uma cláusula except específica.
No exemplo da figura, a exceção está disponível por meio da variável erro, de onde podemos extrair mais informações, como veremos a seguir.
Praticamente todas as exceções em Python são herdadas da classe Exception, ou seja, ela é uma exceção muito genérica, lançada por diversos tipos de erros diferentes. Quanto mais genérica, mais abrangente é a exceção.
Atenção
Não é uma boa prática utilizar exceções abrangentes, pois elas podem silenciar erros que não esperamos. O ideal é tratar as exceções utilizando a forma mais específica possível.
A seguir, apresentamos algumas exceções específicas relacionadas à manipulação de arquivos e alguns motivos que podem gerar essas exceções:
Lançada quando tentamos criar um arquivo ou diretório já existentes.
Lançada quando tentamos abrir um arquivo ou diretório que não existem.
Lançada quando não temos permissão para realizar uma operação
Todas essas exceções herdam da exceção mais abrangente OSError, que, por sua vez, herda de Exception.
Observe o exemplo a seguir, onde vamos tratar a exceção do exemplo anterior, utilizando a exceção específica mais indicada: FileNotFoundError.
Script 23 e sua saída.
O primeiro passo é “envolver” o código que pode gerar problema com o try. Para isso, indentamos as linhas 4 e 5.
Para tratar o erro, precisamos explicitar qual o tipo de erro que vamos tratar. Nesse caso, FileNotFoundError, como descrito na linha 6.
Indentamos as linhas 7 e 8 para indicar que elas fazem parte do escopo da exceção explicitada na linha 6.
Durante a execução do programa, ao executar a linha 4, o Python encontra um erro, pois tentamos abrir o arquivo teste.txt para leitura, mas ele não existe. Como este código está dentro do escopo do try, o interpretador interrompe imediatamente a execução do código contido nesse escopo e inicia a execução do código do except correspondente ao erro FileNotFoundError. Ou seja, a execução salta da linha 4 para a linha 7.
Na linha 7, imprimimos a mensagem "Arquivo inexistente" e, na linha 8, imprimimos o problema encontrado, disponível na variável erro.
Observe a sequência de execução pelas saídas no console.
Saiba que o Python só consegue tratar a exceção caso o erro esteja mapeado em algum except. Se o interpretador não encontrar o except adequado, será gerado um erro, e o programa será interrompido.
Um problema clássico que ocorre quando lidamos com arquivos é tentar alterar o conteúdo de um arquivo quando ele está aberto em outro programa. No caso do sistema operacional Windows 10, é lançada uma exceção sobre permissão de acesso.
No exemplo ao lado, vamos criar mais um except para tratar o caso de não termos permissão para abrir um arquivo, mostrando o tratamento do problema levantado no parágrafo anterior.
Neste exemplo, vamos tentar abrir o arquivo teste.pdf para escrita, linha 4, porém ele já se encontra aberto em outro programa.
Observe que o fluxo de execução do programa saltou da linha 4 para a linha 10. Na linha 10, temos o início do tratamento da exceção PermissionError, que foi justamente a exceção lançada pelo Python, impressa pela linha 11, e que pode ser verificada no console.
Como dito anteriormente, o Python direciona o fluxo de execução para o trecho onde é realizado o tratamento da exceção lançada.
Vamos explorar mais operações referentes a arquivos e diretórios. Aproveitaremos também para mostrar novas exceções que podem ser lançadas quando utilizamos tais operações.
Outras operações em arquivos
Além das opções para leitura e escrita em arquivos, o Python disponibiliza um conjunto de operações adicionais, como renomear e apagar arquivo, além de operações em diretórios, como listar arquivos de diretórios, criar diretórios etc.
A partir de agora, apresentaremos algumas dessas operações.
Vamos iniciar pela operação de remover um arquivo, que está disponível por meio da função remove do módulo os do Python.
A função remove tem a seguinte sintaxe:
>>> os.remove(caminho)
Neste exemplo, temos o nome do módulo os, seguido de um ponto e o nome da função remove. Como parâmetro, a função espera o caminho para um arquivo. Para remover diretório, devemos utilizar outra função, rmdir.
Veja ao lado, onde mostramos a função remove.
Iniciamos o script com a importação do módulo os, na linha 1.
Neste exemplo, vamos remover o arquivo teste.txt, que se encontra no mesmo diretório do nosso script. Observe a arvore de diretórios à esquerda.
Na linha 2, utilizamos a função remove, passando como argumento o caminho do arquivo que desejamos remover. Como estamos no mesmo diretório, utilizamos apenas o nome do arquivo.
Pronto! Isso é suficiente para remover um arquivo.
Dentre as exceções lançadas ao usar a função remove, destacamos as seguintes:
FileNotFoundError
Ocorre quando o arquivo não existe.
PermissionError
Ocorre quando não temos permissão para alterar o arquivo.
IsADirectoryError
Ocorre quando tentamos remover um diretório usando a função remove, em vez de rmdir.
Observe a saída do console, onde tudo ocorreu conforme esperado e nenhuma exceção foi lançada.
A segunda operação que veremos, também muito comum, é a de renomear um arquivo. Essa operação também está disponível no módulo os, mas por meio da função rename.
A função rename tem a seguinte sintaxe:
>>> os.rename(origem, destino)
Nesse exemplo, temos o nome do módulo os, seguido de um ponto e o nome da função rename. Como parâmetro, a função espera o caminho para o arquivo que desejamos renomear, origem, e o novo nome do arquivo, destino.
Veja o exemplo ao lado, em que descrevemos o uso dessa função.
Na linha 1, importamos o módulo os, no qual será utilizada a função rename.
Na linha 4, chamamos a função rename com os parâmetros teste_alfa.txt (origem) e teste_beta.txt (destino). Caso tudo ocorra bem, ao final da operação, teremos apenas o arquivo destino.
A seguir, vamos falar sobre algumas exceções que podem ser lançadas quando utilizamos a função rename. Não estamos tratando todas as opções possíveis, mas apenas as mais comuns.
Ocorre quando a origem não existe.
Ocorre quando não temos permissão para alterar o arquivo de origem ou não temos permissão para escrita do destino.
Ocorre quando o arquivo de destino já existe.
Na figura do nosso exemplo, observe a árvore de diretórios à esquerda. Temos tanto o arquivo teste_alfa.txt quanto o arquivo teste_beta.txt.
Observe a execução do script pelo console e veja que ele saltou da linha 4 para a linha 13. Isso ocorreu porque, como o arquivo teste_beta.txt já existia, a exceção FileExistsError foi lançada.
Dica
Para os casos em que desejamos renomear sobrescrevendo o arquivo destino, caso ele exista, podemos utilizar a função replace, também do módulo os.
Operações em diretórios
Criando e removendo diretórios
Trabalhar com arquivos significa trabalhar com diretórios. Nesta seção, vamos mostrar as principais funcionalidades relacionadas à manipulação de diretórios em Python.
Vamos começar pela criação e remoção de um diretório.
Para criar um diretório, utilizamos a função mkdir do módulo os, enquanto, para remover um diretório, utilizamos a função rmdir, também do módulo os.
A sintaxe dessas duas funções são as seguintes:
>>> os.mkdir(caminho)
>>> os.rmdir(caminho)
Neste exemplo, temos o nome do módulo os, seguido de um ponto e o nome da função mkdir ou rmdir. Como parâmetro, a função espera o caminho para o diretório.
Veja o exemplo a seguir, onde utilizamos essas duas funções.
No script 28, importamos o módulo os na linha 1 e, na linha 4, utilizamos a função mkdir(“meu_diretorio”). O diretório meu_diretorio foi criado na mesma pasta onde o script28 se encontra.
- Caso não tenhamos permissão para criar o diretório, será lançada a exceção PermissionError.
- Caso o diretório já exista, a exceção FileExistsError é lançada.
No script29, na linha 4, utilizamos a função rmdir para remover o diretório meu_diretorio.
- Caso não tenhamos permissão para remover o diretório, será lançada a exceção PermissionError.
- Caso o diretório não exista, a exceção FileNotFoundError é lançada.
Para os casos em que o diretório a ser removido não esteja vazio, será lançada a exceção OSError. Essa exceção é mais abrangente. Por isso, não temos como garantir, a princípio, que a exceção lançada ocorre especificamente pelo fato de o diretório não estar vazio.
Nessas situações, precisamos analisar mais o erro, principalmente o número do erro, para verificar o que realmente aconteceu. O número do erro está disponível no atributo errno do objeto erro.
Os códigos dos possíveis erros estão no módulo errno do Python e podem ser utilizados no tratamento das exceções para descobrir o que realmente deu errado.
No exemplo a seguir, vamos mostrar esse problema mais de perto.
Atenção
Como a exceção OSError é mais abrangente que as outras exceções que estudamos, ela deve ficar por último. Caso contrário, nunca alcançaremos as exceções mais específicas.
Listando conteúdo de diretórios
Outra tarefa muito comum quando estamos tratando com arquivos é listar os arquivos presentes em um diretório.
Para isso, podemos utilizar a função scandir do módulo os. Sua sintaxe é a seguinte:
>>> os.scandir(caminho)
Neste exemplo, temos o nome do módulo os, seguido de um ponto e o nome da função scandir. Como parâmetro, a função espera o caminho para o diretório.
Como resultado, teremos um iterável (iterator) que retorna objetos do tipo os.DirEntry, que podem ser arquivos ou diretórios. Dentre os atributos e métodos desse tipo de objetos, destacamos:
No exemplo a seguir, vamos mostrar como utilizar essa função.
Vídeo com Avaliação
Assista, no vídeo, a explicação sobre manipulação de arquivos e diretórios com Python.
Verificando o aprendizado
ATENÇÃO!
Para desbloquear o próximo módulo, é necessário que você responda corretamente a uma das seguintes questões:
O conteúdo ainda não acabou.
Clique aqui e retorne para saber como desbloquear.
Conclusão
Considerações Finais
Neste tema, visitamos as principais ações que podemos realizar na manipulação de arquivos e diretórios.
Vimos como abrir um arquivo, ler seu conteúdo e escrever novos conteúdos.
Aproveitamos para mostrar funções de manipulação de strings, que são normalmente relacionadas ao tratamento de arquivos, como quebrar linhas em palavras e juntar listas de strings a um conector em particular.
Além disso, entendemos as principais exceções geradas quando estamos trabalhando com arquivos, de forma a tratá-las e garantir o correto funcionamento de nossos programas.
Podcast
CONQUISTAS
Você atingiu os seguintes objetivos:
Identificou as funções de manipulação de arquivos
Reconheceu as funções de manipulação de strings
Descreveu as exceções na manipulação de arquivos e outras operações