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'

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 tertarmos 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 carrera desenvolvedor Python, onde você vai aprender desde o zero até uma aplicação web usando o Python.

(Última atualização em: 29 de maio de 2017)

Content Editor at Alura and Software Developer

  • Andre Nunes

    Indico a Alura excelente empresa com profissionais comprometidos.

    • Alex Felipe

      Opa Andre, muito obrigado pelo feedback!

      []s

Próximo ArtigoComo optar por cursos para seguir carreira na área de 3D?