web-dev-qa-db-ja.com

pythonのmkdir -p機能

Pythonの内部からシェルのmkdir -pのような機能を取得する方法はありますか。システムコール以外の解決策を探しています。私はコードが20行未満であると確信しています、そして誰かがすでにそれを書いたかどうか疑問に思いますか?

688
SetJmp

mkdir -p機能は次のとおりです。

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

更新

Python≥3.2の場合、os.makedirsには オプションの3番目の引数exist_okがあり、trueの場合、mkdir -p機能が有効になります—unlessmodeが提供され、既存のディレクトリには意図したものとは異なる権限があります。その場合、OSErrorは以前と同様に発生します。

更新2

Python≥3.5には、 pathlib.Path.mkdir もあります。

import pathlib

pathlib.Path("/tmp/path/to/desired/directory").mkdir(parents=True, exist_ok=True)

exist_okパラメーターはPython 3.5で追加されました。

997
tzot

Python> = 3.2では、それは

os.makedirs(path, exist_ok=True)

以前のバージョンでは、 @ tzot's answer を使用してください。

229
Fred Foo

これは例外をトラップするよりも簡単です。

import os
if not os.path.exists(...):
    os.makedirs(...)

免責条項 このアプローチは2つのシステムコールを必要とします。制御された環境で実行される単純な使い捨てのスクリプトよりも洗練されたものを書いているのであれば、1つのシステムコールしか必要としないという受け入れられた答えを使ったほうがよいでしょう。

更新2012-07-27

私はこの答えを削除したいのですが、私は以下のコメントスレッドに価値があると思います。そのため、私はそれをWikiに変換しています。

150
Joe Holloway

最近、私はこれを見つけました distutils.dir_util.mkpath

In [17]: from distutils.dir_util import mkpath

In [18]: mkpath('./foo/bar')
Out[18]: ['foo', 'foo/bar']
47
auraham

ファイルが既に存在する場合、mkdir -pはエラーを返します。

$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory `/tmp/foo': File exists

そのため、os.path.isdirraiseを返す場合(errno.EEXISTをチェックするとき)、以前の提案を改良して例外を-Falseにすることになります。

(更新)こちらも参照してください 非常によく似た質問 ;私はos.path.isdirの代わりにos.path.existsを推薦する以外は、受け入れられた答え(および警告)に同意します。

(更新)コメントの提案によると、フル機能は次のようになります。

import os
def mkdirp(directory):
    if not os.path.isdir(directory):
        os.makedirs(directory) 
18

Pathlib を使ってpython3標準ライブラリから:

Path(mypath).mkdir(parents=True, exist_ok=True)

両親が正しい場合は、このパスに足りない両親が必要に応じて作成されます。それらはモードを考慮に入れずにデフォルトのパーミッションで作成されます(POSIX mkdir -pコマンドを真似て)。 exist_okがfalse(デフォルト)の場合、ターゲットディレクトリがすでに存在する場合はFileExistsErrorが送出されます。

Exist_okがtrueの場合、FileExistsError例外は無視されます(POSIXのmkdir -pコマンドと同じ動作)。ただし、最後のパスコンポーネントが既存のディレクトリ以外のファイルでない場合のみです。

バージョン3.5で変更された仕様: exist_okパラメータが追加されました。

14
Ali SAID OMAR

他の解決策で述べたように、私たちはmkdir -pの振る舞いを真似ている間にファイルシステムを一度ヒットできるようにしたいです。私はこれが可能であるとは思わないが、我々はできるだけ近くなるべきである。

最初にコーディングし、後で説明します。

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

@ tzotの回答に対するコメントが示すように、実際にディレクトリを作成する前にディレクトリを作成できるかどうかを確認することには問題があります。その間に誰かがファイルシステムを変更したかどうかはわかりません。これは、許可ではなく、許しを求めるPythonのスタイルにも当てはまります。

だから私たちが最初にすべきことはディレクトリを作成しようとすることです、そしてそれがうまくいかなかったら、それを解決してください。

Jacob Gabrielsonが指摘しているように、私たちが探さなければならないケースの1つは、ディレクトリを配置しようとしている場所にファイルが既に存在するケースです。

mkdir -pの場合:

$ touch /tmp/foo
$ mkdir -p /tmp/foo
mkdir: cannot create directory '/tmp/foo': File exists

Pythonの同様の動作は例外を発生させることです。

そうであるならば、我々は解決しなければなりません。残念ながら、できません。ディレクトリが存在する(good)か、ディレクトリの作成を妨げるファイルが存在する(bad)かにかかわらず、makedirsから同じエラーメッセージが返されます。

起こったことを解決する唯一の方法はディレクトリがそこにあるかどうか見るためにファイルシステムを再度点検することです。もしあれば、静かに戻って、そうでなければ例外を発生させます。

唯一の問題は、makedirsが呼び出されたときとはファイルシステムが異なる状態になっている可能性があることです。例:ファイルが存在してmakedirが失敗しましたが、今度はその場所にディレクトリがあります。最後のファイルシステム呼び出しの時点でディレクトリが存在していた場合、関数は例外を発生させずに静かに終了するだけなので、それはそれほど重要ではありません。

14
c4m3lo

Asaの答えは本質的に正しいと思いますが、mkdir -pのように振る舞うように少し拡張することもできます。

import os

def mkdir_path(path):
    if not os.access(path, os.F_OK):
        os.mkdirs(path)

または

import os
import errno

def mkdir_path(path):
    try:
        os.mkdirs(path)
    except os.error, e:
        if e.errno != errno.EEXIST:
            raise

これらは両方とも、パスがすでに静かに存在しているが、他のエラーが発生することを許容している場合を扱います。

12
davidavr

関数宣言

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

使用法 :

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))
7
Guray Celik

私は個人的には次のようなことに成功しましたが、私の関数はおそらく「このディレクトリが存在することを確認する」のような名前で呼ばれるべきです。

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
4
Dave C
import os
import tempfile

path = tempfile.mktemp(dir=path)
os.makedirs(path)
os.rmdir(path)
3
pixelbeat
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)

@Dave Cの答えに基づいていますが、ツリーの一部がすでに存在する場所にバグが修正されています

2
Dave00Galloway