سؤال

هذا السؤال لديه بالفعل إجابة هنا:

هل هناك طريقة للحصول على وظائف مماثلة ل mkdir -p على الصدفة من داخل بايثون.أنا أبحث عن حل آخر غير استدعاء النظام.أنا متأكد من أن الكود أقل من 20 سطرًا، وأتساءل عما إذا كان شخص ما قد كتبه بالفعل؟

هل كانت مفيدة؟

المحلول

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

تحديث

بالنسبة لبيثون ≥ 3.2، os.makedirs لديه الوسيطة الثالثة الاختيارية exist_ok أنه، عندما يكون صحيحا، تمكن mkdir -p وظائف -إلا إذا mode يتم توفيره والدليل الحالي له أذونات مختلفة عن تلك المقصودة؛في هذه الحالة، OSError مرفوع كما سبق .

تحديث 2

بالنسبة لبيثون ≥ 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.

نصائح أخرى

في بايثون >=3.2، هذا هو

os.makedirs(path, exist_ok=True)

في الإصدارات السابقة، استخدم إجابة @tzot.

هذا أسهل من محاصرة الاستثناء:

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

تنصل يتطلب هذا الأسلوب استدعاءين للنظام يكونان أكثر عرضة لظروف السباق في ظل بيئات/ظروف معينة.إذا كنت تكتب شيئًا أكثر تعقيدًا من مجرد نص برمجي بسيط يتم تشغيله في بيئة خاضعة للرقابة، فمن الأفضل أن تستخدم الإجابة المقبولة التي تتطلب استدعاء نظام واحدًا فقط.

تحديث 2012/07/27

أميل إلى حذف هذه الإجابة، ولكن أعتقد أن هناك قيمة في سلسلة التعليقات أدناه.وعلى هذا النحو، أقوم بتحويله إلى ويكي.

لقد وجدت هذا مؤخرًا distutils.dir_util.mkpath:

In [17]: from distutils.dir_util import mkpath

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

mkdir -p يعطيك خطأ إذا كان الملف موجودًا بالفعل:

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

لذا فإن تنقيح الاقتراحات السابقة سيكون بمثابة إعادة -raise الاستثناء إذا os.path.isdir عائدات False (عند التحقق من errno.EEXIST).

(تحديث) انظر هذا أيضًا سؤال مشابه للغاية;أتفق مع الإجابة المقبولة (والتحذيرات) إلا أنني أوصي os.path.isdir بدلاً من os.path.exists.

(تحديث) وفقًا لاقتراح في التعليقات، ستبدو الوظيفة الكاملة كما يلي:

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

كما هو مذكور في الحلول الأخرى، نريد أن نكون قادرين على ضرب نظام الملفات مرة واحدة أثناء محاكاة سلوك 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 إلى وجود مشكلات في التحقق مما إذا كان بإمكانك إنشاء دليل قبل إنشائه بالفعل:لا يمكنك معرفة ما إذا كان شخص ما قد قام بتغيير نظام الملفات في هذه الأثناء.يتناسب هذا أيضًا مع أسلوب بايثون في طلب المغفرة، وليس الإذن.

لذا فإن أول شيء يجب علينا فعله هو محاولة إنشاء الدليل، ثم إذا حدث خطأ ما، فاكتشف السبب.

كما يشير جاكوب غابرييلسون، إحدى الحالات التي يجب أن نبحث عنها هي الحالة التي يوجد فيها ملف بالفعل حيث نحاول وضع الدليل.

مع mkdir -p:

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

سيكون السلوك المماثل في بايثون هو إثارة استثناء.

لذلك علينا أن نعرف ما إذا كان هذا هو الحال.لسوء الحظ، لا نستطيع ذلك.نحصل على نفس رسالة الخطأ من makedirs سواء كان الدليل موجودًا (جيدًا) أو كان هناك ملف يمنع إنشاء الدليل (سيء).

الطريقة الوحيدة لمعرفة ما حدث هي فحص نظام الملفات مرة أخرى لمعرفة ما إذا كان هناك دليل هناك.فإن كان هناك فارجع بصمت، وإلا ارفع الاستثناء.

المشكلة الوحيدة هي أن نظام الملفات قد يكون في حالة مختلفة الآن عما كان عليه عندما تم استدعاء makedirs.على سبيل المثال:يوجد ملف يتسبب في فشل makedirs، ولكن الآن يوجد دليل في مكانه.هذا لا يهم كثيرًا حقًا، لأن الوظيفة ستخرج فقط بصمت دون إثارة استثناء عندما يكون الدليل موجودًا في وقت آخر استدعاء لنظام الملفات.

مع باثليب من مكتبة python3 القياسية:

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

If parents is true, any missing parents of this path are created as needed; they are created with the default permissions without taking mode into account (mimicking the POSIX mkdir -p command). If exist_ok is false (the default), an FileExistsError is raised if the target directory already exists.

If exist_ok is true, FileExistsError exceptions will be ignored (same behavior as the POSIX mkdir -p command), but only if the last path component is not an existing non-directory file.

تم التغيير في الإصدار 3.5: تمت إضافة المعلمة موجودة.

أعتقد أن إجابة 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

كلاهما يتعامل مع الحالة التي يكون فيها المسار موجودًا بالفعل بصمت ولكن يسمح للأخطاء الأخرى بالظهور.

إعلان الوظيفة؛

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

لقد حققت نجاحًا مع ما يلي شخصيًا، ولكن ربما ينبغي تسمية وظيفتي بشيء مثل "التأكد من وجود هذا الدليل":

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)

بناءً على إجابة @ Dave C ولكن مع إصلاح الخلل حيث يوجد جزء من الشجرة بالفعل

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top