- sáb 04 março 2023
- utils
- Giliard Godoi
- #python, #pathlib
As vezes eu tenho uma dúvida muito simples sobre o funcionamento de uma função ou método do Python. Então eu crio esses guias rápidos, no estilo “Perguntas e Respostas” para me ajudar a evitar uma pesquisa no Google.
Nesse guia eu trato sobre o pacote para manipulação de diretórios e arquivos pathlib
.
Perguntas e Respostas
Como importar?
from pathlib import Path
Como representar um caminho?
>>> from pathlib import Path
>>> foo = Path('foo')
Como saber se o diretório ou arquivo existe?
>>> foo = Path('script.py')
>>> foo.exists()
False
Retorna True
ou False
.
Como saber se é um arquivo ou um diretório?
>>> foo = Path('foo')
>>> foo.is_dir()
True
>>> bar = Path('script.py')
>>> bar.is_file()
True
>>> bar.is_dir()
False
Importante notar, entretanto, que se o arquivo ou o diretório realmente não existe no sistema operacional, os métodos is_file
e is_dir
sempre retornarão False
.
Como saber o nome de um arquivo\diretório ?
>>> foo = Path('bar\script.py')
>>> foo.name
>>> 'script.py'
Como criar um arquivo?
Como criar um arquivo no sistema de arquivo.
>>> foo = Path('script.py')
>>> foo.touch()
Esse método também pode ser usado para alterar o timestamp de um arquivo que já existia previamente.
Como remover um arquivo?
>>> bar = Path('main.py')
>>> bar.unlink()
Como renomear um arquivo?
>>> foo = Path('script.py')
>>> bar = foo.rename('main.py')
Ou então:
>>> bar = foo.rename(Path('main.py'))
Lembre-se que estamos trabalhando com objetos imutáveis.
Então, a operação de rename
retorna um novo objeto.
Essa operação é refletida no sistema de arquivos do seu computador.
Diferente da próxima opção, mostrada a seguir.
Também podemos nos referir a um mesmo arquivo com um nome diferente, mas que não necessáriamente existe no FS do computador. Poderíamos renomea-lo de forma virtual somente.
>>> foo = Path('script.py')
>>> bar = foo.with_name('main.py')
>>> bar.exists()
False
>>> foo.exists()
True
>>> bar.touch()
>>> bar.exists()
True
Isso simplifica como fazer cópias de um mesmo arquivo, talvez?
Como saber a extensão de um arquivo?
Com o atributo .suffix
>>> foo = Path('script.py')
>>> foo.suffix
'.py'
Ou com o atributo suffixes
que retorna uma lista nos casos de:
>>> foo = Path('library.tar.gar')
>>> foo.suffixes
['.tar', '.gar']
Como ler e escrever texto em um arquivo?
Existem vários modos de se fazer isso.
A maneira mais direta é utilizando os métodos write_text
e read_text
>>> foo = Path('README.md')
>>> foo.write_text('Some text here!')
15
>>> foo.exists()
True
>> foo.read_text()
"Some text here!"
Também podemos fazer algo parecido com os métodos write_bytes
e read_bytes
para arquivos binários.
Como criar um diretório novo?
foo = Path('foo')
foo.mkdir()
Como listar os arquivos ou subdiretórios a partir do diretório atual?
Podemos iterar com ajuda do método iterdir()
foo = Path('tutorial')
directories = [f for f in foo.iterdir() if f.is_dir()]
Ou com a ajuda do método glob
que aceita uma string com o padrão de nomes que queremos percorrer.
foo = Path('tutorial')
# lista todos os arquivos e subdiretórios do diretório atual
foo.glob("*")
# retorna todos os arquivos com a extensão .ipynb do diretório atual
foo.glob("*.ipynb")
# retorna todos os arquivos e subdiretórios a partir do diretório atual
foo.glob("**/*")
O método rglob
server como um atalho para glob
com a string **/
já adicionada à direita do padrão passado como parâmetro.
>>> foo.rglob('*.ipynb')
# possui o mesmo efeito que
>>> foo.glob("**/*.ipynb")
Lembre-se que os métodos iterdir
, glob
e rglob
retornam um iterador e não a lista propriamente dita.
Como remover um diretório?
Se o diretório está vazio, basta o comando:
>>> foo = Path('foo')
>>> foo.rmdir()
Caso o diretório não esteja vazio, tem-se duas opções:
A primeira é remover todos os arquivos e subdiretórios a partir do diretório atual, utilizando recursão e um a um.
Ou então podemos utilizar a função shutil.rmtree
do módulo shutil
.
Como concatenar o nome de um diretório como um nome de um subdiretório ou um arquivo?
Podemos utilizar o operador /
como no exemplo a seguir:
>>> foo = Path('foo')
>>> foo / 'bar' / 'test' / 'test_script.py'
>>> foo
WindowsPath('foo/bar/test/test_script.py')
Com o método joinpath
>>> foo = Path('foo')
>>> foo.joinpath('bar', 'test', 'test_script.py')
WindowsPath('foo/bar/test/test_script.py')
Ou então, diretamente na inicialiação do objeto:
>>> foo = Path('foo', 'bar', 'test', 'test_script.py')
Por incrível que parece o operador de adição +
não retorna a concatenação de vários caminhos.
Como saber o diretório pai de um arquivo ou diretório?
Podemos tentar algo como:
>>> foo = Path('foo')
>>> foo.parent # retorna o primeiro diretório pai
>>> # ou então
>>> foo.parents # retorna um gerador para os diretórios pais
Mas isso pode retorna uma resposta como WindowsPath('.')
caso o arquivo não exista ou foi criado depois que a variável foi inicializada.
Porém, podemos recuperar o diretório pai de diretório atual de onde esse arquivo foi criado:
>>> foo = Path('foo')
>>> foo.resolve().parent # retorna o primeiro diretório pai
WindowsPath('folder')
>>>
>>> foo.resolve().parents # retorna um gerador
<WindowsPath.parents>
Também podemos recuperar essas informações com o atributo parts
:
>>> foo = Path('folder/script.py')
>>> foo.resolve().parts
('folder', 'script.py')
Como saber o diretório de trabalho atual?
>>> from pathlib import Path
>>> Path.cwd()
'/home/user/folder_x'
Também conhecido como current working diretory ou cwd
.
Exemplos
Os dois exemplos a seguir foram visto nesse post do blog Real Python . 1. Contar os arquivos em um diretório atual, agrupado pela extensão do arquivo; 2. Mostrar a estrutura de diretórios.
Contar arquivos
O primeiro snippet de código mostra como contar os arquivos conforme as suas extensões:
>>> from collections import Counter
>>> Counter(p.suffix for p in Path.cwd().iterdir() if p.is_file())
Counter({'.html': 7, '.png': 6, '.xml': 1, '.ico': 1, '.md': 1, '.webmanifest': 1})
Mostrar a estrutura de diretórios
O segundo mostra um forma de criar uma visualização no terminal para a estrutura de diretórios.
def tree(directory):
print(f'+ {directory}')
for path in sorted(directory.rglob('*')):
depth = len(path.relative_to(directory).parts)
spacer = ' ' * depth
print(f'{spacer}+ {path.name}')
tree(Path.cwd())
Para saber mais
Para saber mais sobre o módulo pathlib
, além da página da documentação, eu recomendo essa live do Dunossauro do Canal Live de Python sobre Manipulação de arquivos e pastas com pathlib - Live de Python #199 - YouTube.
Referências
- Python Documentation. pathlib — Object-oriented filesystem paths. Disponível em: https://docs.python.org/3/library/pathlib.html Acessado em: 14 de fev. de 2023.
- Eduardo Mendes: Live de Python. Manipulação de arquivos e pastas com pathlib - Live de Python #199 . Disponível em: https://www.youtube.com/watch?v=E_hox7iZjOE Acessado em 14 de fev. de 2023.
- Real Python. Python 3’s pathlib Module: Taming the File System . Disponível em https://realpython.com/python-pathlib/ Acessado em 14 de fev. de 2023.