Mkdir -p funcionalidade em Python [duplicado]
Pergunta
Esta questão já tem uma resposta aqui:
Existe uma maneira de obter uma funcionalidade semelhante ao mkdir -p
no shell de dentro Python. Eu estou procurando uma solução que não seja uma chamada de sistema. Estou certo que o código é menos de 20 linhas, e eu estou querendo saber se alguém já escreveu isso?
Solução
funcionalidade mkdir -p
da seguinte forma:
import errno
import os
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
Atualização
Para Python = 3,2, os.makedirs
tem um opcional terceiro argumento exist_ok
que, quando verdadeiro, permite a funcionalidade mkdir -p
- menos mode
é fornecido eo diretório existente tem permissões diferentes dos pretendidos; nesse caso, OSError
é levantada como anteriormente.
Update 2
Para Python = 3,5, há também pathlib.Path.mkdir
:
import pathlib
pathlib.Path("/tmp/path/to/desired/directory").mkdir(parents=True, exist_ok=True)
O parâmetro exist_ok
foi adicionado em Python 3.5.
Outras dicas
Em Python> = 3,2, que é
os.makedirs(path, exist_ok=True)
Em versões anteriores, use de @ tzot resposta .
Esta é mais fácil do que prendendo a exceção:
import os
if not os.path.exists(...):
os.makedirs(...)
Aviso Esta abordagem requer duas chamadas de sistema que é mais suscetível a condições de corrida sob certas ambientes / condições. Se você estiver escrevendo algo mais sofisticado do que um script descartável simples em execução em um ambiente controlado, você é melhor fora de ir com a resposta aceita que requer apenas uma chamada de sistema.
Atualização 2012-07-27
Estou tentado excluir esta resposta, mas eu acho que há valor no segmento de comentário abaixo. Como tal, eu estou convertendo-a em uma wiki.
Recentemente, eu encontrei este distutils.dir_util.mkpath :
In [17]: from distutils.dir_util import mkpath
In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']
mkdir -p
lhe dá um erro se o arquivo já existe:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists
Assim, um refinamento para as sugestões anteriores seria a re-raise
a exceção se os.path.isdir
retornos False
(durante a verificação de errno.EEXIST
).
(Update) Veja também este altamente semelhantes pergunta ; Concordo com a resposta aceita (e advertências), exceto eu recomendaria os.path.isdir
vez de os.path.exists
.
(Update) Por uma sugestão nos comentários, a função completa seria algo como:
import os
def mkdirp(directory):
if not os.path.isdir(directory):
os.makedirs(directory)
Como mencionado em outras soluções, queremos ser capaz de bater o sistema de arquivos uma vez enquanto imitando o comportamento de mkdir -p
. Eu não acho que isso é possível fazer, mas devemos chegar tão perto quanto possível.
Código primeiro, a explicação mais tarde:
import os
import errno
def mkdir_p(path):
""" 'mkdir -p' in Python """
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
Como os comentários a resposta de @ tzot indicam que há problemas com a verificação se você pode criar um diretório antes de realmente criá-lo: você não pode dizer se alguém mudou o sistema de arquivos no mesmo período. Isso também se encaixa com o estilo de pedir perdão, não permissão de Python.
Assim, a primeira coisa que devemos fazer é tentar fazer com que o diretório, em seguida, se der errado, o trabalho o porquê.
Como aponta Jacob Gabrielson, um dos casos devemos procurar é o caso em que já existe um ficheiro onde estamos tentando colocar o diretório.
Com mkdir -p
:
$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory '/tmp/foo': File exists
O comportamento análogo em Python seria elevar uma excepção.
Por isso, temos de trabalhar para fora se este era o caso. Infelizmente, nós não podemos. Nós obter o mesmo erro mensagem de volta de makedirs se existe um diretório (bom) ou existe um arquivo de impedir a criação do diretório (mau).
A única maneira de descobrir o que aconteceu é inspecionar o sistema de arquivos novamente para ver se há um diretório lá. Se houver, em seguida, retornar silenciosamente, caso contrário, aumentar a exceção.
O único problema é que o sistema de arquivo pode estar em um estado diferente agora do que quando makedirs foi chamado. por exemplo: um arquivo existia causando makedirs a falhar, mas agora um diretório está em seu lugar. Isso realmente não importa muito, porque a função só vai sair em silêncio, sem levantar uma exceção quando no momento do último sistema de arquivos chamar o diretório existia.
Com Pathlib de python3 biblioteca padrão:
Path(mypath).mkdir(parents=True, exist_ok=True)
Se os pais é verdade, nenhum pais ausentes deste caminho são criados como necessário; eles são criados com as permissões padrão sem tomar Modo em conta (imitando o comando POSIX mkdir -p). Se exist_ok é falso (o padrão), um FileExistsError é gerado se o diretório de destino já existe.
Se exist_ok é verdade, exceções FileExistsError será ignorado (mesmo comportamento como o comando mkdir -p POSIX), mas somente se o último caminho componente não é um arquivo não-diretório existente.
alterado na versão 3.5:. O parâmetro exist_ok foi adicionado
Eu acho que a resposta de Asa é essencialmente correta, mas você pode estendê-lo um pouco para agir mais como mkdir -p
, ou:
import os
def mkdir_path(path):
if not os.access(path, os.F_OK):
os.mkdirs(path)
ou
import os
import errno
def mkdir_path(path):
try:
os.mkdirs(path)
except os.error, e:
if e.errno != errno.EEXIST:
raise
Estes dois lidar com o caso onde o caminho já existe em silêncio, mas deixe os outros erros borbulhar.
declaração Function;
import os
def mkdir_p(filename):
try:
folder=os.path.dirname(filename)
if not os.path.exists(folder):
os.makedirs(folder)
return True
except:
return False
uso:
filename = "./download/80c16ee665c8/upload/backup/mysql/2014-12-22/adclient_sql_2014-12-22-13-38.sql.gz"
if (mkdir_p(filename):
print "Created dir :%s" % (os.path.dirname(filename))
Eu tive sucesso com o seguinte pessoalmente, mas minha função provavelmente deve ser chamado algo como 'garantir este diretório existe':
def mkdirRecursive(dirpath):
import os
if os.path.isdir(dirpath): return
h,t = os.path.split(dirpath) # head/tail
if not os.path.isdir(h):
mkdirRecursive(h)
os.mkdir(join(h,t))
# end mkdirRecursive
import os
import tempfile
path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)
import os
from os.path import join as join_paths
def mk_dir_recursive(dir_path):
if os.path.isdir(dir_path):
return
h, t = os.path.split(dir_path) # head/tail
if not os.path.isdir(h):
mk_dir_recursive(h)
new_path = join_paths(h, t)
if not os.path.isdir(new_path):
os.mkdir(new_path)
com base na resposta do @ Dave C, mas com um bug fixo onde parte da árvore já existe