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?

Foi útil?

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top