Manipulação de Caminhos de Arquivos e Diretórios
Para um mergulho profundo em operações práticas do sistema de arquivos, confira nossa postagem no blog: 10 Operações Essenciais do Sistema de Arquivos que Todo Desenvolvedor Deve Conhecer.
Existem dois módulos principais em Python que lidam com a manipulação de caminhos. Um é o módulo os.path e o outro é o módulo pathlib.
Pathlib vs Módulo OS
pathlib fornece muito mais funcionalidade do que as listadas acima, como obter o nome do arquivo, obter a extensão do arquivo, ler/escrever um arquivo sem abri-lo manualmente, etc. Consulte a documentação oficial se você pretende saber mais.
Caminhos Linux e Windows
No Windows, os caminhos são escritos usando barras invertidas (\) como separador entre nomes de pastas. Em sistemas operacionais baseados em Unix, como macOS, Linux e BSDs, a barra normal (/) é usada como separador de caminho. Juntar caminhos pode ser um aborrecimento se o seu código precisar funcionar em diferentes plataformas.
Felizmente, o módulo pathlib do Python oferece uma maneira fácil de lidar com isso.
Usando pathlib em *nix:
# pathlib.Path: manipulação de caminho multiplataforma
from pathlib import Path
print(Path('usr').joinpath('bin').joinpath('spam')) # Junta componentes do caminho
usr/bin/spam
pathlib também fornece um atalho para joinpath usando o operador /:
# Operador Path (/): maneira conveniente de juntar caminhos (multiplataforma)
from pathlib import Path
print(Path('usr') / 'bin' / 'spam') # Usa o operador / em vez de joinpath()
usr/bin/spam
Note que o separador de caminho é diferente entre Windows e sistemas operacionais baseados em Unix, é por isso que você deseja usar pathlib em vez de adicionar strings juntas para juntar caminhos.
Faça login para responder este quiz e acompanhar seu progresso de aprendizagem
Path('usr') + 'bin' + 'spam'Path('usr') / 'bin' / 'spam'Path('usr').join('bin').join('spam')Path('usr/bin/spam')Juntar caminhos é útil se você precisar criar caminhos de arquivo diferentes sob o mesmo diretório.
Usando pathlib em *nix:
# Path.home(): obter o diretório inicial do usuário, combinar com nomes de arquivos
my_files = ['accounts.txt', 'details.csv', 'invite.docx']
home = Path.home() # Obtém o caminho do diretório inicial
for filename in my_files:
print(home / filename) # Combina o caminho inicial com cada nome de arquivo
/home/labex/project/accounts.txt
/home/labex/project/details.csv
/home/labex/project/invite.docx
Expandindo o diretório inicial do usuário
Usando os.path.expanduser() para expandir ~ para o diretório inicial do usuário:
import os.path
# Expande ~ para o diretório inicial do usuário
print(os.path.expanduser('~'))
/home/labex/project
# Expande ~/Documents para o caminho completo
print(os.path.expanduser('~/Documents'))
/home/labex/project/Documents
# Funciona com caminhos contendo ~
print(os.path.expanduser('~/myfile.txt'))
/home/labex/project/myfile.txt
O diretório de trabalho atual
Você pode obter o diretório de trabalho atual usando pathlib:
# Path.cwd(): obter o diretório de trabalho atual
from pathlib import Path
print(Path.cwd()) # Retorna o diretório de trabalho atual como um objeto Path
/home/labex/project
Criação de novas pastas
Usando pathlib em *nix:
from pathlib import Path
cwd = Path.cwd()
(cwd / 'delicious' / 'walnut' / 'waffles').mkdir()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/pathlib.py", line 1226, in mkdir
self._accessor.mkdir(self, mode)
File "/usr/lib/python3.6/pathlib.py", line 387, in wrapped
return strfunc(str(pathobj), *args)
FileNotFoundError: [Errno 2] No such file or directory: '/home/labex/project/delicious/walnut/waffles'
Oh não, recebemos um erro chato! O motivo é que o diretório ‘delicious’ não existe, então não podemos criar os diretórios ‘walnut’ e ‘waffles’ sob ele. Para corrigir isso, faça:
# mkdir(parents=True): cria o diretório e todos os diretórios pais, se necessário
from pathlib import Path
cwd = Path.cwd()
(cwd / 'delicious' / 'walnut' / 'waffles').mkdir(parents=True) # Cria diretórios aninhados
E tudo fica bem :)
Caminhos Absolutos vs. Relativos
Existem duas maneiras de especificar um caminho de arquivo.
- Um caminho absoluto, que sempre começa com a pasta raiz
- Um caminho relativo, que é relativo ao diretório de trabalho atual do programa
Existem também as pastas ponto (.) e ponto-ponto (..). Estas não são pastas reais, mas nomes especiais que podem ser usados em um caminho. Um único ponto (“ponto”) para um nome de pasta é um atalho para “este diretório”. Dois pontos (“ponto-ponto”) significam “a pasta pai”.
Manipulação de caminhos absolutos
Para ver se um caminho é um caminho absoluto usando pathlib:
from pathlib import Path
Path('/').is_absolute()
True
Path('..').is_absolute()
False
Faça login para responder este quiz e acompanhar seu progresso de aprendizagem
Path('/').is_absolute() retorna?TrueFalseNone'/'Você pode extrair um caminho absoluto com pathlib:
from pathlib import Path
print(Path.cwd())
/home/labex/project
print(Path('..').resolve())
/home
Manipulação de caminhos relativos
Você pode obter um caminho relativo de um caminho inicial para outro caminho usando pathlib:
from pathlib import Path
print(Path('/etc/passwd').relative_to('/'))
etc/passwd
Validade de Caminho e Arquivo
Verificando se um arquivo/diretório existe
Usando pathlib em *nix:
from pathlib import Path
Path('.').exists()
True
Path('setup.py').exists()
True
Path('/etc').exists()
True
Path('nonexistentfile').exists()
False
Verificando se um caminho é um arquivo
Usando pathlib em *nix:
from pathlib import Path
Path('setup.py').is_file()
True
Path('/home').is_file()
False
Path('nonexistentfile').is_file()
False
Faça login para responder este quiz e acompanhar seu progresso de aprendizagem
Path('setup.py').is_file() retornará se setup.py existir?'setup.py'FalseTrueNoneVerificando se um caminho é um diretório
Usando pathlib em *nix:
from pathlib import Path
Path('/').is_dir()
True
Path('setup.py').is_dir()
False
Path('/spam').is_dir()
False
Obtendo o tamanho de um arquivo em bytes
Usando pathlib em *nix:
from pathlib import Path
stat = Path('/bin/python3.6').stat()
print(stat) # stat contém algumas outras informações sobre o arquivo também
os.stat_result(st_mode=33261, st_ino=141087, st_dev=2051, st_nlink=2, st_uid=0,
--snip--
st_gid=0, st_size=10024, st_atime=1517725562, st_mtime=1515119809, st_ctime=1517261276)
print(stat.st_size) # tamanho em bytes
10024
Listando diretórios
Listando o conteúdo do diretório usando pathlib em *nix:
from pathlib import Path
for f in Path('/usr/bin').iterdir():
print(f)
...
/usr/bin/tiff2rgba
/usr/bin/iconv
/usr/bin/ldd
/usr/bin/cache_restore
/usr/bin/udiskie
/usr/bin/unix2dos
/usr/bin/t1reencode
/usr/bin/epstopdf
/usr/bin/idle3
...
Tamanhos de arquivos de diretório
AVISO
Diretórios também têm um tamanho! Portanto, você pode querer verificar se um caminho é um arquivo ou diretório usando os métodos discutidos na seção acima.
Usando pathlib em *nix:
from pathlib import Path
total_size = 0
for sub_path in Path('/usr/bin').iterdir():
total_size += sub_path.stat().st_size
print(total_size)
1903178911
Copiando arquivos e pastas
O módulo shutil fornece funções para copiar arquivos, bem como pastas inteiras.
import shutil
shutil.copy('/tmp/spam.txt', '/tmp/delicious')
/tmp/delicious/spam.txt
shutil.copy('/tmp/eggs.txt', '/tmp/delicious/eggs2.txt')
/tmp/delicious/eggs2.txt
Faça login para responder este quiz e acompanhar seu progresso de aprendizagem
shutil.copy()Path.copy()os.copy()shutil.copytree()Enquanto shutil.copy() copiará um único arquivo, shutil.copytree() copiará uma pasta inteira e todas as pastas e arquivos contidos nela:
import shutil
shutil.copytree('/tmp/bacon', '/tmp/bacon_backup')
/tmp/bacon_backup
Movendo e Renomeando
import shutil
shutil.move('/tmp/bacon.txt', '/tmp/eggs')
/tmp/eggs/bacon.txt
O caminho de destino também pode especificar um nome de arquivo. No exemplo a seguir, o arquivo de origem é movido e renomeado:
shutil.move('/tmp/bacon.txt', '/tmp/eggs/new_bacon.txt')
/tmp/eggs/new_bacon.txt
Se não houver pasta eggs, então move() renomeará bacon.txt para um arquivo chamado eggs:
shutil.move('/tmp/bacon.txt', '/tmp/eggs')
/tmp/eggs
Excluindo arquivos e pastas
- Chamar
Path.unlink()excluirá o arquivo no caminho. - Chamar
Path.rmdir()excluirá a pasta no caminho. Esta pasta deve estar vazia de quaisquer arquivos ou pastas. - Chamar
shutil.rmtree(path)removerá a pasta no caminho, e todos os arquivos e pastas que ela contém também serão excluídos.
Faça login para responder este quiz e acompanhar seu progresso de aprendizagem
Path.rmdir()shutil.rmtree()Path.unlink()os.remove()Percorrendo uma Árvore de Diretórios
O objeto Path tem um método rglob() para iterar recursivamente sobre arquivos e diretórios.
from pathlib import Path
p = Path('/tmp/delicious')
for i in p.rglob('*'):
print(i)
/tmp/delicious/cats
/tmp/delicious/walnut
/tmp/delicious/spam.txt
/tmp/delicious/cats/catnames.txt
/tmp/delicious/cats/zophie.jpg
/tmp/delicious/walnut/waffles
/tmp/delicious/walnut/waffles/butter.txt