モジュール Pythonで入れ子ディレクトリを安全に作成するにはどうすればよいですか?




python モジュール 化 (20)

ファイルI / Oを操作する場合、重要な考慮事項は次のとおりです。

TOCTTOU(利用時間のチェックの時間)

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

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

ファイルが書き込まれるディレクトリが存在するかどうかを調べる最もエレガントな方法は何ですか?存在しない場合は、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 (thanks kanja、Blair、Douglas)を見逃してしまった。 これは今私が持っているものです:

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

これが自動的に行われるようにするために、 "open"のフラグがありますか?


良質の2つの回答があり、それぞれに小さな欠陥があるので、私はそれに取り組んでいきます:

os.path.exists試し、作成のためにos.makedirsを検討してください。

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

コメントなどに記載されているように、競合条件が存在します。ディレクトリがos.path.existsos.makedirs間で作成されると、 os.makedirsos.makedirs失敗します。 残念ながら、不十分なアクセス許可、フルディスクなど、他の要因によってディレクトリが作成されないという問題は無視されるため、包括的な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が存在する可能性がありますが、別のos.path.existsが存在する可能性がありますが、もう1つは最初のチェックの後にディレクトリを作成し、2番目のチェックの前に削除したとします。

アプリケーションに応じて、同時操作の危険性は、ファイルのアクセス権などの他の要因によって引き起こされる危険よりも多かれ少なかれ発生する可能性があります。 開発者は、実装を選択する前に、開発中の特定のアプリケーションとその期待される環境についてもっと知る必要があります。


1行のソリューションでは、 IPython.utils.path.ensure_dir_exists()使用できます。

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

documentationから: ディレクトリが存在することを確認します。 存在しない場合は、作成し、別のプロセスが同じことを行っている場合は競合状態から保護してください。


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からexists_okフラグを取得したのとexists_okです)。


os.makedirs確認してください(完全なパスが存在することを確認します)。
ディレクトリが存在する可能性があるという事実を処理するには、OSErrorをキャッチします。 (exists_okがFalse(デフォルト)の場合、ターゲットディレクトリがすでに存在する場合はOSErrorが発生します)。

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

次の点を考慮する場合:

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

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


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.path.exists()テストすると、その引数をos.makedirs()渡すと、 filename.etcという名前のディレクトリが作成されfilename.etc


このコマンドを使用してチェックを行い、dirを作成します

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

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

このディレクトリ構造を考えてみましょう:

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

ここに私の実験/ノートがあります。

# ----------------------------------------------------------------------------
# [1] https://.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] os.makedirs


プログラム/プロジェクトのエントリポイントで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')

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

ここであなたのコードは、(タッチ)コマンドを使用しています

これは、ファイルが存在しない場合はそこに存在するかどうかをチェックし、存在しない場合は作成します。


これにはos.listdirを使うことができます:

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

os.path.exists()を使用します。 hereは、ディレクトリが存在するかどうかをチェックし、存在しない場合は作成し、存在する場合は削除します(必要な場合)。

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


私は次のことを断った。 しかし、それは完全に確実ではない。

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

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


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.EACCES (Permission denied、error 13)で発生したerrno.EACCES発生します。


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

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

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

特定のパスに特定のファイルを指定し、ファイルパスからそのディレクトリをプルします。 その後、ディレクトリがあることを確認した後、読み込み用のファイルを開こうとします。 このコードにコメントするには:

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

組み込み関数dir上書きしないようにしたい。 また、 filepathまたはおそらくfullfilepathfilenameよりも意味のある名前である可能性が高いので、これはより良い記述になります:

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

あなたの最終的な目標は、最初に書いておいたこのファイルを開くことですが、基本的にこの目的(コードに基づいています)に近づいています。

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モードで開く(または追加する)必要があることに注意してください。 また、ファイルを開くためにコンテキストマネージャを使用することも、Pythonのベストプラクティスです。

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

しかし、すべてのデータを同じディレクトリに置くことを試みるいくつかのPythonプロセスがあるとします。 次に、ディレクトリの作成に競合する可能性があります。 その場合は、try-exceptブロックでmakedirs呼び出しをラップすることをおmakedirsます。

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)

シェル言語をサポートしているマシンで実行している場合は、サブプロセスモジュールを使用しないでください。 Python 2.7とPython 3.6で動作します。

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

ほとんどのシステムでそのトリックを行う必要があります。


私はHeikki Toivonenとshareの答えを見て、このバリエーションを考えました。

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

あなたは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で動作します。







operating-system