web-dev-qa-db-ja.com

Pythonでネストされたディレクトリを安全に作成する方法

ファイルが書き込まれるディレクトリが存在するかどうかを確認し、存在しない場合はPythonを使用してディレクトリを作成する最もエレガントな方法は何ですか?これが私が試したものです:

import os

file_path = "/my/directory/filename.txt"
directory = os.path.dirname(file_path)

try:
    os.stat(directory)
except:
    os.mkdir(directory)       

f = file(filename)

どういうわけか、私はos.path.existsを逃しました(ありがとうkanja、Blair、そしてDouglas)。これは私が今持っているものです:

def ensure_dir(file_path):
    directory = os.path.dirname(file_path)
    if not os.path.exists(directory):
        os.makedirs(directory)

"open"のフラグがありますか?

3548
Parand

質の良い2つの答えがあり、それぞれに小さな欠陥があります。そのため、私はそれについて考えます。

os.path.exists を試してみて、 os.makedirs を考えてみてください。

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

コメントなどで述べたように、競合条件があります - ディレクトリがos.path.existsos.makedirsの呼び出しの間に作成された場合、os.makedirsOSErrorで失敗します。残念ながら、OSErrorを包括的にとらえ続けて継続することは、パーミッション不足、フルディスクなどの他の要因によるディレクトリ作成の失敗を無視するため、絶対確実というわけではありません。

1つの選択肢はOSErrorをトラップして埋め込まれたエラーコードを調べることです( PythonのOSErrorから情報を得るためのクロスプラットフォームな方法はありますか )。

import os, errno

try:
    os.makedirs(directory)
except OSError as e:
    if e.errno != errno.EEXIST:
        raise

別の方法として、2番目のos.path.existsがあるかもしれませんが、最初のチェックの後に別のディレクトリが作成され、次に2番目のチェックの前にそのディレクトリが削除されたとします。 

アプリケーションによっては、並行操作の危険性が、ファイル許可などの他の要因によってもたらされる危険性よりも多い場合も少ない場合もあります。開発者は、実装を選択する前に、開発中の特定のアプリケーションとその予想される環境についてさらに知る必要があります。

最近のバージョンのPythonでは、 FileExistsError (3.3以降)を公開することで、このコードがかなり改善されています。

try:
    os.makedirs("path/to/directory")
except FileExistsError:
    # directory already exists
    pass

...と os.makedirsへのキーワード引数であるexist_ok を許可することにより(3.2以降)。

os.makedirs("path/to/directory", exist_ok=True)  # succeeds even if directory exists.
4171
Blair Conrad

Python 3.5以降:

import pathlib
pathlib.Path('/my/directory').mkdir(parents=True, exist_ok=True) 

pathlib.Path.mkdir 上記のように再帰的にディレクトリを作成し、そのディレクトリがすでに存在する場合は例外を発生させません。親を作成する必要がない場合、または作成する必要がない場合は、parents引数をスキップしてください。

Python 3.2以降:

pathlibを使用する:

可能であれば、 pathlib2 という名前の現在のpathlibバックポートをインストールします。 pathlib という名前の古い保守されていないバックポートをインストールしないでください。次に、上記のPython 3.5以降のセクションを参照して、同じように使用してください。

Python 3.4を使用している場合、たとえpathlibが付いていても、便利なexist_okオプションが欠けています。バックポートは、この欠けているオプションを含むmkdirのより新しく優れた実装を提供することを目的としています。

osを使用する:

import os
os.makedirs(path, exist_ok=True)

os.makedirs 上記のように再帰的にディレクトリを作成し、そのディレクトリがすでに存在する場合は例外を発生させません。 Python 3.2+を使用している場合にのみオプションのexist_ok引数があり、デフォルト値はFalseです。この引数はPython 2.xから2.7までには存在しません。そのため、Python 2.7のように手動で例外を処理する必要はありません。

Python 2.7以降:

pathlibを使用する:

可能であれば、 pathlib2 という名前の現在のpathlibバックポートをインストールします。 pathlib という名前の古い保守されていないバックポートをインストールしないでください。次に、上記のPython 3.5以降のセクションを参照して、同じように使用してください。

osを使用する:

import os
try: 
    os.makedirs(path)
except OSError:
    if not os.path.isdir(path):
        raise

単純な解決法では最初に os.path.isdir に続けて os.makedirs を使用することができますが、上記の解決法では2つの操作の順序が逆になります。そうすることで、それは一般的な競合状態がディレクトリを作成しようとする重複した試みと関係があることを防ぎ、またディレクトリからのファイルを明確にします。

OSError: [Errno 17] File exists、すなわちerrno.EEXISTはファイルとディレクトリの両方に対して発生するので、例外を捕捉してerrnoを使用することは、有用性が限られていることに注意してください。単にディレクトリが存在するかどうかを確認する方が信頼性が高いです。

代替案

mkpath はネストしたディレクトリを作成し、そのディレクトリがすでに存在する場合は何もしません。これはPython 2と3の両方で動作します。

import distutils.dir_util
distutils.dir_util.mkpath(path)

Per バグ10948 、この選択肢の深刻な制限は、与えられたパスに対してpythonプロセスごとに一度だけ動作することです。言い換えれば、それを使ってディレクトリを作成してから、そのディレクトリをPythonの内側または外側から削除し、もう一度mkpathを使って同じディレクトリを再作成すると、mkpathは単に以前にディレクトリを作成したという無効なキャッシュ情報を使用します。実際には再びディレクトリを作成することはありません。対照的に、os.makedirsはそのようなキャッシュに依存しません。この制限はアプリケーションによっては問題ないかもしれません。


ディレクトリのmodeに関しては、気にしているのならドキュメントを参照してください。

1010
A-B-B

Try exceptとerrnoモジュールからの正しいエラーコードを使用することは競合状態を取り除き、クロスプラットフォームです:

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise

言い換えれば、我々はディレクトリを作成しようとします、しかし、それらがすでに存在するならば、我々はエラーを無視します。一方、他のエラーは報告されます。たとえば、dir 'a'を事前に作成し、そこからすべての許可を削除すると、errno.EACCESOSErrorが発生します(Permission denied、エラー13)。

589
Heikki Toivonen

個人的にはos.path.isdir()の代わりにos.path.exists()を使ってテストすることをお勧めします。

>>> os.path.exists('/tmp/dirname')
True
>>> os.path.exists('/tmp/dirname/filename.etc')
True
>>> os.path.isdir('/tmp/dirname/filename.etc')
False
>>> os.path.isdir('/tmp/fakedirname')
False

あなたが持っている場合:

>>> dir = raw_input(":: ")

そして愚かなユーザー入力:

:: /tmp/dirname/filename.etc

... os.makedirs()でテストした場合、その引数をos.path.exists()に渡すと、filename.etcという名前のディレクトリになります。

92
crimsonstone

os.makedirs :をチェックします(完全なパスが存在することを確認します)。
ディレクトリが存在する可能性があることを処理するために、OSErrorをキャッチします(exist_okがFalse(デフォルト)の場合、ターゲットディレクトリが既に存在する場合はOSErrorが送出されます)

import os
try:
    os.makedirs('./path/to/somewhere')
except OSError:
    pass
66
Douglas Mayle

Python 3.5以降、 pathlib.Path.mkdir にはexist_okフラグがあります。

from pathlib import Path
path = Path('/my/directory/filename.txt')
path.parent.mkdir(parents=True, exist_ok=True) 
# path.parent ~ os.path.dirname(path)

これは再帰的にディレクトリを作成し、ディレクトリがすでに存在する場合は例外を発生させません。

(ちょうど os.makedirs がpython 3.2から始まるexist_okフラグを取得したのと同じです。例えばos.makedirs(path, exist_ok=True)

47

この状況の詳細についての洞察

特定のファイルを特定のパスに配置し、そのファイルパスからディレクトリを取り出します。次に、ディレクトリがあることを確認した後、ファイルを読み取り用に開こうとします。このコードについてコメントするには:

filename = "/my/directory/filename.txt"
dir = os.path.dirname(filename)

組み込み関数dirを上書きしないようにします。また、filepathまたはおそらくfullfilepathはおそらくfilenameよりも優れたセマンティック名です。

import os
filepath = '/my/directory/filename.txt'
directory = os.path.dirname(filepath)

あなたの最終的な目標は、このファイルを書くことで開くことです、あなたは最初に、記述のために述べています、しかし、あなたは本質的にこのようにreadingのためにファイルを開く、

if not os.path.exists(directory):
    os.makedirs(directory)
f = file(filename)

読書のための開放を想定

なぜあなたはそこにいて読むことができると期待するファイルのためのディレクトリを作るのでしょうか? 

ファイルを開こうとするだけです。

with open(filepath) as my_file:
    do_stuff(my_file)

ディレクトリまたはファイルが存在しない場合は、関連するエラー番号を含むIOErrorが表示されます。プラットフォームに関係なく、errno.ENOENTは正しいエラー番号を指します。あなたが望むなら、あなたはそれをキャッチすることができます、例えば:

import errno
try:
    with open(filepath) as my_file:
        do_stuff(my_file)
except IOError as error:
    if error.errno == errno.ENOENT:
        print 'ignoring error because directory or file is not there'
    else:
        raise

我々が執筆のために開いていると仮定

これは おそらく あなたが欲しいものです。

この場合、おそらく競合状況に直面していません。なので、ちょうどあなたがしたようにしてください、しかし書くことのために、あなたはwモード(または追加するためにa)で開く必要があることに注意してください。ファイルを開くためにコンテキストマネージャを使用することもPythonのベストプラクティスです。

import os
if not os.path.exists(directory):
    os.makedirs(directory)
with open(filepath, 'w') as my_file:
    do_stuff(my_file)

しかし、すべてのデータを同じディレクトリに配置しようとするいくつかのPythonプロセスがあるとします。それから、ディレクトリの作成について競合があるかもしれません。その場合はmakedirs呼び出しをtry-exceptブロックでラップするのが最善です。

import os
import errno
if not os.path.exists(directory):
    try:
        os.makedirs(directory)
    except OSError as error:
        if error.errno != errno.EEXIST:
            raise
with open(filepath, 'w') as my_file:
    do_stuff(my_file)
36
Aaron Hall

os.path.exists 関数を試してください。

if not os.path.exists(dir):
    os.mkdir(dir)
30
gone

私は次のことを書き留めました。それは完全に絶対確実というわけではありません。

import os

dirname = 'create/me'

try:
    os.makedirs(dirname)
except OSError:
    if os.path.exists(dirname):
        # We are nearly safe
        pass
    else:
        # There was an error on creation, so make sure we know about it
        raise

私が言うように、これは本当に絶対確実というわけではありません。なぜなら、ディレクトリを作成できない可能性と、その間に別のプロセスがディレクトリを作成する可能性があるからです。

27
Ali Afshar

ディレクトリが存在するかどうかを確認し、必要に応じて作成しますか?

これに対する直接的な答えは、他のユーザやプロセスがあなたのディレクトリをめちゃくちゃにすることを期待していない単純な状況を想定していることです。

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

または ディレクトリの作成が競合状態の影響を受ける場合(つまり、パスの確認後に別のものがすでに作成している場合)、次のようにします。

import errno
try:
    os.makedirs(d)
except OSError as exception:
    if exception.errno != errno.EEXIST:
        raise

しかし、おそらくもっと良いアプローチは、 tempfile を介して一時ディレクトリを使用することで、リソースの競合問題を回避することです。

import tempfile

d = tempfile.mkdtemp()

これがオンラインドキュメントの要点です。

mkdtemp(suffix='', prefix='tmp', dir=None)
    User-callable function to create and return a unique temporary
    directory.  The return value is the pathname of the directory.

    The directory is readable, writable, and searchable only by the
    creating user.

    Caller is responsible for deleting the directory when done with it.

Python 3.5の新機能:pathlib.Pathexist_ok

パスで使用したいと思う多くのメソッドを持つ新しいPathオブジェクト(3.4現在)があります - そのうちの1つはmkdirです。

(コンテキストとして、私はスクリプトで私の毎週の担当者を追跡しています。これは、同じデータに対して1日に1回以上スタックオーバーフローが発生するのを避けるためのスクリプトの関連部分です。)

まず関連する輸入品:

from pathlib import Path
import tempfile

今はos.path.joinを扱う必要はありません。パス部分を/で結合するだけです。

directory = Path(tempfile.gettempdir()) / 'sodata'

それから私はたぶんディレクトリが存在することを確認します - exist_ok引数はPython 3.5で現れます:

directory.mkdir(exist_ok=True)

これは ドキュメント の関連部分です。

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

これはもう少しスクリプトを追加したものです - 私の場合、競合状態の影響を受けません。ディレクトリ(または含まれているファイル)が存在することを想定したプロセスが1つだけです。ディレクトリ 

todays_file = directory / str(datetime.datetime.utcnow().date())
if todays_file.exists():
    logger.info("todays_file exists: " + str(todays_file))
    df = pd.read_json(str(todays_file))

Pathパスを必要とする他のAPIがそれらを使用できるようにするには、strオブジェクトをstrに強制変換する必要があります。

おそらくPandasは抽象基底クラスos.PathLikeのインスタンスを受け入れるように更新されるべきです。

20
Aaron Hall

Python 3.4では 真新しいpathlibモジュール を使うこともできます。

from pathlib import Path
path = Path("/my/directory/filename.txt")
try:
    if not path.parent.exists():
        path.parent.mkdir(parents=True)
except OSError:
    # handle error; you can also catch specific errors like
    # FileExistsError and so on.
17
Antti Haapala

関連するPythonドキュメント - EAFPコーディングスタイル(パーミッションより許しを求める方が簡単)の使用を示唆しています 。これはコードが

try:
    os.makedirs(path)
except OSError as exception:
    if exception.errno != errno.EEXIST:
        raise
    else:
        print "\nBE CAREFUL! Directory %s already exists." % path

代替よりも優れている

if not os.path.exists(path):
    os.makedirs(path)
else:
    print "\nBE CAREFUL! Directory %s already exists." % path

ドキュメンテーションはまさしくこの質問で議論された競争条件のためにこれを示唆します。さらに、他の人がここで言及しているように、OSの2倍ではなく1回の照会にはパフォーマンス上の利点があります。最後に、潜在的に、アプリケーションが実行されている環境を開発者が知っているときに2番目のコードに有利になるという主張が提唱されるのは、プログラムがプライベート環境を設定したという特別な場合だけです。それ自体(および同じプログラムの他のインスタンス)。

その場合でも、これは悪い習慣であり、長く役に立たないデバッグにつながる可能性があります。たとえば、ディレクトリのアクセス許可を設定したという事実が、インプレッションのアクセス許可を持っていてはいけません。目的に合わせて適切に設定します。親ディレクトリは他の権限でマウントされる可能性があります。一般に、プログラムは常に正しく機能し、プログラマーは特定の環境を期待するべきではありません。

12
kavadias

Python3 では、os.makedirsexist_okの設定をサポートします。デフォルト設定はFalseです。これは、ターゲットディレクトリがすでに存在する場合はOSErrorが発生することを意味します。 exist_okTrueに設定すると、OSError(directory exists)は無視され、ディレクトリは作成されません。

os.makedirs(path,exist_ok=True)

Python2 では、os.makedirsexist_okの設定をサポートしていません。 heikki-toivonen's answer :でアプローチを使うことができます。

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise
8
euccas

mkpath を使用できます

# Create a directory and any missing ancestor directories. 
# If the directory already exists, do nothing.

from distutils.dir_util import mkpath
mkpath("test")    

先祖ディレクトリも作成されることに注意してください。 

Python 2と3で動作します。

8

私はos.path.exists()を使用します、 here はディレクトリが存在するかどうかをチェックし、存在しない場合は作成し、存在する場合は削除するために使用できるPython 3スクリプトです(必要に応じて).

ユーザーにディレクトリの入力を促し、簡単に変更できます。

7
Michael Strobel

ワンライナーソリューションの場合は、IPython.utils.path.ensure_dir_exists()を使用できます。

from IPython.utils.path import ensure_dir_exists
ensure_dir_exists(dir)

のドキュメントから ディレクトリが存在することを確認してください。それが存在しない場合は、それを作成し、他のプロセスが同じことをしている場合は競合状態から保護するようにしてください。

7
tashuhka

Heikki Toivonen そして A-B-B の答えを見て、この変化について考えました。

import os
import errno

def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST or not os.path.isdir(path):
            raise
6
alissonmuller

ファイルI/Oを扱うときに考慮すべき重要なことは

TOCTTOU(チェック時から使用時まで)

そのため、ifでチェックして、後で読み書きすると、未処理のI/O例外が発生する可能性があります。それを行うための最善の方法は次のとおりです。

try:
    os.makedirs(dir_path)
except OSError as e:
    if e.errno != errno.EEXIS:
        raise
6
SHAHS

これにはos.listdirを使用できます。

import os
if 'dirName' in os.listdir('parentFolderPath')
    print('Directory Exists')
6
iPhynx

私はこのQ/Aを見つけました、そして、私は最初私が得ていた失敗とエラーのいくつかに困惑しました。私はPython 3(Arch Linux x86_64システム上のAnaconda仮想環境のv.3.5)で働いています。

このディレクトリ構造を考慮してください。

└── output/         ## dir
   ├── corpus       ## file
   ├── corpus2/     ## dir
   └── subdir/      ## dir

これが私の実験やメモです。

# ----------------------------------------------------------------------------
# [1] https://stackoverflow.com/questions/273192/how-can-i-create-a-directory-if-it-does-not-exist

import pathlib

""" Notes:
        1.  Include a trailing slash at the end of the directory path
            ("Method 1," below).
        2.  If a subdirectory in your intended path matches an existing file
            with same name, you will get the following error:
            "NotADirectoryError: [Errno 20] Not a directory:" ...
"""
# Uncomment and try each of these "out_dir" paths, singly:

# ----------------------------------------------------------------------------
# METHOD 1:
# Re-running does not overwrite existing directories and files; no errors.

# out_dir = 'output/corpus3'                ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/'               ## works
# out_dir = 'output/corpus3/doc1'           ## no error but no dir created (missing tailing /)
# out_dir = 'output/corpus3/doc1/'          ## works
# out_dir = 'output/corpus3/doc1/doc.txt'   ## no error but no file created (os.makedirs creates dir, not files!  ;-)
# out_dir = 'output/corpus2/tfidf/'         ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/'         ## works
# out_dir = 'output/corpus3/a/b/c/d/'       ## works

# [2] https://docs.python.org/3/library/os.html#os.makedirs

# Uncomment these to run "Method 1":

#directory = os.path.dirname(out_dir)
#os.makedirs(directory, mode=0o777, exist_ok=True)

# ----------------------------------------------------------------------------
# METHOD 2:
# Re-running does not overwrite existing directories and files; no errors.

# out_dir = 'output/corpus3'                ## works
# out_dir = 'output/corpus3/'               ## works
# out_dir = 'output/corpus3/doc1'           ## works
# out_dir = 'output/corpus3/doc1/'          ## works
# out_dir = 'output/corpus3/doc1/doc.txt'   ## no error but creates a .../doc.txt./ dir
# out_dir = 'output/corpus2/tfidf/'         ## fails with "Errno 20" (existing file named "corpus2")
# out_dir = 'output/corpus3/tfidf/'         ## works
# out_dir = 'output/corpus3/a/b/c/d/'       ## works

# Uncomment these to run "Method 2":

#import os, errno
#try:
#       os.makedirs(out_dir)
#except OSError as e:
#       if e.errno != errno.EEXIST:
#               raise
# ----------------------------------------------------------------------------

結論:私の意見では、「方法2」のほうが堅牢です。

[1] ディレクトリが存在しない場合、どうすれば作成できますか?

[2] https://docs.python.org/3/library/os.html#os.makedirs

6
Victoria Stuart

次のことを考慮してください。 

os.path.isdir('/tmp/dirname')

ディレクトリ(パス)が存在し、かつディレクトリであることを意味します。だから私にとっては、このようにして私が必要とすることができます。だから私はそれがフォルダ(ファイルではない)であり、存在することを確認することができます。

3
Ralph Schwerdt

Pathlibライブラリを使用する

import pathlib
mypath="/my/directory"
pathlib.Path(mypath).mkdir(parents=True, exist_ok=True) 
2

プログラム/プロジェクトの入り口で関数create_dir()を呼び出します。

import os

def create_dir(directory):
    if not os.path.exists(directory):
        print('Creating Directory '+directory)
        os.makedirs(directory)

create_dir('Project directory')
2

このコマンドcheckを使用してdirを作成します

 if not os.path.isdir(test_img_dir):
     os.mkdir(str("./"+test_img_dir))

ディレクトリを作成する前にフルパスを設定する必要があります。

import os,sys,inspect
import pathlib

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
your_folder = currentdir + "/" + "your_folder"

if not os.path.exists(your_folder):
   pathlib.Path(your_folder).mkdir(parents=True, exist_ok=True)

これは私のために機能し、うまくいけば、それはあなたのためにも機能します

0
Hussam Kurd
import os
if os.path.isfile(filename):
    print "file exists"
else:
    "Your code here"

あなたのコードがここにあるところでは(touch)コマンドを使用します

これは、ファイルが存在しているかどうかを確認し、存在していない場合は作成します。

0
Evil Exists

シェル言語をサポートするマシン上で実行している場合、サブプロセスモジュールを使用しないのはなぜですか? python 2.7およびpython 3.6で動作します

from subprocess import call
call(['mkdir', '-p', 'path1/path2/path3'])

ほとんどのシステムでトリックをするべきです。

0