Trabalhando com arquivos e diretórios no python

Trabalhando com arquivos e diretórios no python

No meu sistema de cadastro de produtos, preciso criar uma funcionalidade que, a partir de um arquivo CSV com dados dos produtos, eu consigo ler esse arquivo e separar todos os produtos contido nele. Para representar um produto temos a seguinte classe:


class Produto(object): 
  def __init__(self, nome, valor): 
    self.__nome = nome 
    self.__valor = valor

  @property 
  def nome(self): 
    return self.__nome

  @nome.setter 
  def nome(self, nome): 
    self.__nome = nome

  @property def valor(self): 
    return self.__valor

  @valor.setter 
  def valor(self, valor): 
    self.__valor = valor 

  def __repr__(self): 
    return "nome:%s valor:%s" % (self.__nome, self.__valor)

Inicialmente temos o arquivo dados.csv com o seguinte conteúdo:

 nome, valor camiseta, 25.0 jaqueta, 125.0 tenis, 80.0 bermuda, 40.0

Nesse meu sistema, irei ler esse arquivo a partir do diretório "arquivos/produtos/" portanto, criaremos a variável arquivo indicando o caminho e o nome do arquivo que leremos:


arquivo = 'arquivo/produtos/dados.csv'

Implementando a função de leitura do arquivo

Agora precisamos criar uma função que ficará responsável em ler esses produtos por meio da variável arquivo, portanto, criaremos a função ler_produtos() passando o arquivo como parâmetro:


def ler_produtos(arquivo):

arquivo = 'arquivo/produtos/dados.csv'

Primeiro, precisamos abrir o arquivo CSV, ou seja, utilizaremos a função open enviando a variável arquivo e utilizando parâmetro 'rb' que indica leitura:


def ler_produtos(arquivo):
   arquivo_aberto = open(arquivo, 'rb')

No Python, para ler um arquivo CSV, podemos utilizar a função reader do módulo csv, porém, precisamos importar o módulo:


import csv

def ler_produtos(arquivo): 
  arquivo_aberto = open(arquivo, 'rb') 
  return csv.reader(arquivo_aberto,delimiter=',')

Observe que também adicionamos o parâmetro delimiter que já separa cada informação a partir de um critério, nesse caso, cada informação será separada no momento em que aparecer uma vírgula, e também, estamos retornando a função reader que é justamente o arquivo lido.

Então vamos realizar um teste, faremos a chamada para a função ler_produtos e devolveremos para a variável dados:


import csv

def ler_produtos(arquivo): 
  arquivo_aberto = open(arquivo, 'rb') 
  return csv.reader(arquivo_aberto,delimiter=',')

arquivo = 'arquivo/produtos/dados.csv'

dados = ler_produtos(arquivo)

Rodando o nosso código temos o seguinte resultado:

 IOError: [Errno 2] No such file or directory: 'arquivo/produtos/dados.csv'
Banner da Escola de Programação: Matricula-se na escola de Programação. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!

Verificando a existência do arquivo

Opa! Ele não conseguiu achar o meu arquivo! Por que será que isso aconteceu? Vejamos dentro do diretório onde está o meu projeto:

 > ls dados.csv model.py verificando_diretorio.py

De fato não existe esse diretório, então o que devemos fazer? Antes mesmo de tentarmos pegar o arquivo, temos que verificar se ele pelo menos existe! Em outras palavras, precisamos primeiro verificar se o caminho que queremos encontrar existe, caso não exista, precisamos criá-lo!

Portanto, o nosso primeiro passo é separar a variável arquivo em duas, ou seja, a arquivo e caminho:


caminho = 'arquivo/produtos' 
arquivo = caminho + '/dados.csv'

Em seguida, vamos criar a função verificar_arquivo, que será responsável em verificar se o diretório existe e o arquivo também, caso não exista, ela deverá criá-los! Então vamos criá-la:


import csv

def verificar_arquivo(): 
  caminho = 'arquivo/produtos' arquivo = caminho + '/dados.csv'

def ler_produtos(arquivo): 
  arquivo_aberto = open(arquivo, 'rb')
  return csv.reader(arquivo_aberto,delimiter=',')

dados = ler_produtos(arquivo)

Verificando a existência do diretório

Qual é o nosso próximo passo? É justamente verificar se o diretório não existe. Para isso, no Python, podemos utilizar o módulo os com funções capazes de realizar chamadas de sistema.

Nesse nosso primeiro caso, utilizaremos a função path.exists que verifica se existe um arquivo ou diretório com o parâmetro informado:


import csv import os

def verificar_arquivo(): 
  caminho = 'arquivo/produtos' 
  arquivo = caminho + '/dados.csv'

if not os.path.exists(caminho):

Observe que estamos varificando se o diretório não existe, caso isso for verdade, o que devemos fazer? Precisamos criar o diretório! Mas como criamos um diretório no Python? Simples! No modulo os, temos também a função makedirs que cria diretórios:


def verificar_arquivo(): 
  caminho = 'arquivo/produtos' 
  arquivo = caminho + '/dados.csv'

if not os.path.exists(caminho):
   os.makedirs(caminho)

O nosso próximo passo é verificar a existência do arquivo dentro desse diretório. Podemos utilizar novamente a função path.exists do módulo os. Da mesma forma como fizemos com o diretório, caso não exista o arquivo, precisamos criá-lo.

Criando o arquivo

Para criar um arquivo, utilizaremos a função open passando o segundo parâmetro com o valor "w" que indica a criação para escrita:


def verificar_arquivo(): 
  caminho = 'arquivo/produtos' 
  arquivo = caminho + '/dados.csv'

if not os.path.exists(caminho): 
  os.makedirs(caminho)
if not os.path.exists(arquivo): 
  open(arquivo, 'w')

Por fim, retornamos a variável arquivo para lermos na função ler_produtos:


def verificar_arquivo(): 
  caminho = 'arquivo/produtos' 
  arquivo = caminho + '/dados.csv'

  if not os.path.exists(caminho): 
    os.makedirs(caminho)

  if not os.path.exists(arquivo): 
    open(arquivo, 'w')

  return arquivo

Agora, basta apenas chamarmos a função verificar_arquivo devolvendo o seu resultado para a variável arquivo, e então, chamamos a função ler_produtos enviando a variável arquivo como parâmetro:


arquivo = verificar_arquivo() dados = ler_produtos(arquivo)

Exibindo as informações

Agora vamos imprimir os dados para verificar os valores, porém, ao invés de fazer um for de forma procedural, utilizaremos o recurso de compreensão de lista:


print [dado for dado in dados]

Executando o código temos o seguinte resultado:

 [['nome', ' valor'],
 ['camiseta', ' 25.0'],
 ['jaqueta', ' 125.0'], 
 ['tenis', ' 80.0'],
 ['bermuda', ' 40.0']]

Note que o primeiro valor ainda é o cabeçalho, isto é, linhas 'nome' e 'valor'. Para eliminarmos esse cabeçalho basta chamarmos a função next antes de iterar a variável dados:


next(dados) print [dado for dado in dados]

Por fim, basta apenas armazenarmos os valores em objetos do tipo Produto:


produtos = [Produto(dado[0], dado[1]) for dado in dados] print produtos

Rodando o código novamente, temos o seguinte resultado:

[nome:camiseta valor: 25.0,
nome:jaqueta valor: 125.0,
nome:tenis valor: 80.0,
nome:bermuda valor: 40.0]

Situações inesperadas

Observe que todos os dados foram lidos sem nenhum problema! Entretanto, se o caminho "arquivo/produtos" ao invés de ser um diretório, fosse um arquivo? O que será que aconteceria com o nosso código?

Vamos fazer uma simulação! Primeiro eu vou alterar o nome do diretório para "arquivo/produtos" para "arquivo/produtos1" e então, vou criar um arquivo chamado "produtos" dentro do diretório "arquivo":

arquivo_sem_extensao

Testando o nosso código, temos o seguinte resultado:

 Traceback (most recent call last): File "/home/alex-felipe/python/dir.py", line 22, in <module> arquivo = verificar_arquivo() 

 File "/home/alex-felipe/python/dir.py", line 14, in verificar_arquivo open(arquivo, 'w') IOError: \[Errno 20\] Not a directory: 'arquivo/produtos/dados.csv'

Veja que ele tentou abrir o arquivo com a função open porém percebeu que o "arquivo/produtos" trata-se de um arquivo! Em outras palavras, permitimos que o nosso algoritmo seguisse adiante... Então o que devemos fazer?

Antes mesmo do nosso algoritmo tentar abrir o arquivo, precisamos garantir que o caminho é válido! Portanto, logo no momento que verificamos se não existe o caminho:


if not os.path.exists(caminho): os.makedirs(caminho)

Podemos adicionar uma elfi que será acionado caso exista um arquivo ou diretório de acordo com o caminho especificado, e então, vai verificar se o caminho não é um diretório:


if not os.path.exists(caminho): os.makedirs(caminho) elif not os.path.isdir(caminho):

Caso for verdade, ou seja, o caminho especificado não for um diretório, simplesmente lançamos um erro de IOError avisando que o caminho que estamos utilizando não é um diretório:


if not os.path.exists(caminho): os.makedirs(caminho) elif not os.path.isdir(caminho): raise IOError(caminho + " nao eh um diretorio!")

Agora, quando existir um arquivo ou diretório no caminho especificado e não for um diretório, automaticamente paramos o nosso algoritmo! Vejamos o resultado no teste:

 Traceback (most recent call last): File "/home/alex-felipe/python/dir.py", line 22, in <module> arquivo = verificar_arquivo() File "/home/alex-felipe/python/dir.py", line 11, in verificar_arquivo raise IOError(caminho + " nao eh um diretorio!") IOError: arquivo/produtos nao eh um diretorio!

Veja que agora, mesmo em casos exceptionais como este, o nosso algoritmo consegue lidar e tomar as decisões necessárias.

Conclusão

Nesse post, vimos os problemas que podemos ter durante a leitura de arquivos dentro de diretórios, isto é, antes de tentarmos realizar a leitura de um arquivo precisamos sempre verificar se o caminho, nesse caso diretório, e o arquivo realmente existem, caso não, precisamos criá-los, caso sim, apenas lemos!

Gostou da dica? Então compartilhe conosco o que achou nos comentários :)

E que tal aprender a desenvolver com o Python hoje mesmo? Na Alura, temos a cursos de Python, onde você vai aprender desde o zero até uma aplicação web usando o Python.

Alex Felipe
Alex Felipe

Alex é instrutor e desenvolvedor e possui experiência em Java, Kotlin, Android. Criador de mais de 40 cursos, como Kotlin, Flutter, Android, persistência de dados, comunicação com Web API, personalização de telas, testes automatizados, arquitetura de Apps e Firebase. É expert em Programação Orientada a Objetos, visando sempre compartilhar as boas práticas e tendências do mercado de desenvolvimento de software. Atuou 2 anos como editor de conteúdo no blog da Alura e hoje ainda escreve artigos técnicos.

Veja outros artigos sobre Programação