python - المحجوزة - انواع البيانات في البايثون



كيف يمكنني إنشاء دليل متداخل بأمان في Python؟ (17)

ما هي الطريقة الأكثر أناقة لفحص ما إذا كان الدليل سيتم كتابة ملف موجود ، وإذا لم يكن كذلك ، قم بإنشاء الدليل باستخدام بايثون؟ هذا ما جربته:

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 ، بلير ، ودوغلاس). هذا ما لدي الآن:

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

هل هناك علم "مفتوح" ، ما يجعل هذا يحدث تلقائيًا؟

https://code.i-harness.com


تحقق مما إذا كان هناك دليل موجود وإنشاء إن لزم الأمر؟

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

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 الموارد ، وذلك باستخدام أدلة مؤقتة عبر 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.Path with exist_ok

هناك كائن Path جديد (اعتبارا من 3.4) مع الكثير من الأساليب التي قد يرغب المرء في استخدامها مع المسارات - واحد منها هو mkdir .

(بالنسبة للسياق ، أقوم بتتبع ممثلي الأسبوعية باستخدام برنامج نصي. إليك الأجزاء ذات الصلة من التعليمات البرمجية من النص البرمجي التي تسمح لي بتجنب ضرب أكثر من مرة واحدة في اليوم لنفس البيانات.)

أولا الواردات ذات الصلة:

from pathlib import Path
import tempfile

ليس علينا التعامل مع os.path.join الآن - فقط ضم أجزاء المسار باستخدام / :

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

بعد ذلك ، exist_ok وجود الدليل - تظهر الوسيطة exist_ok في Python 3.5:

directory.mkdir(exist_ok=True)

إليك الجزء ذو الصلة من pathlib.Path.mkdir :

إذا كانت exist_ok صحيحة ، سيتم تجاهل استثناءات FileExistsError (نفس سلوك الأمر POSIX mkdir -p ) ، ولكن فقط إذا لم يكن مكون المسار الأخير ملفًا غير دليل موجود.

إليك المزيد من النص - في حالتي ، أنا لست خاضعًا لشرط سباق ، ليس لدي سوى عملية واحدة تتوقع أن يكون الدليل (أو الملفات المضمنة) موجودًا ، وليس لدي أي شيء يحاول إزالته الدليل.

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 إلى str قبل APIs الأخرى التي تتوقع مسارات str يمكن استخدامها.

ربما يجب تحديث Pandas لقبول os.PathLike الطبقة الأساسية المجردة ، os.PathLike .


رؤى حول تفاصيل هذا الوضع

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

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)

هدفك النهائي هو فتح هذا الملف ، الذي تنص عليه في البداية ، للكتابة ، ولكنك تقترب من هذا الهدف بشكل أساسي (بناءً على شفرتك) مثل هذا ، والذي يفتح الملف للقراءة :

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 (أو إلحاق). كما أنها من أفضل ممارسات بايثون استخدام مدير السياق لفتح الملفات.

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

ومع ذلك ، لنفترض أن لدينا العديد من عمليات بايثون التي تحاول وضع جميع بياناتها في نفس الدليل. ثم قد يكون لدينا خلاف حول إنشاء الدليل. في هذه الحالة ، من الأفضل أن makedirs مكالمة 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)

أرى إجابتين لهما صفات جيدة ، كل منهما به عيب صغير ، لذا سأعطيه الأمر:

حاول os.path.exists ، والنظر os.makedirs للإبداع.

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

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

قد يكون أحد الخيارات هو اعتراض OSError وفحص رمز الخطأ المضمن (راجع هل هناك طريقة عبر النظام الأساسي للحصول على معلومات من OSError Python ):

import os, errno

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

بدلاً من ذلك ، يمكن أن يكون هناك os.path.exists ثانيًا ، لكن لنفترض أن آخرًا أنشأ الدليل بعد التحقق الأول ، ثم os.path.exists الثاني - لا يزال من الممكن خداعنا.

اعتمادا على التطبيق ، قد يكون خطر العمليات المتزامنة أكثر أو أقل من الخطر الذي تشكله عوامل أخرى مثل أذونات الملفات. سيتعين على المطور معرفة المزيد عن التطبيق المعين الذي يجري تطويره وبيئة العمل المتوقعة قبل اختيار التنفيذ.


أستخدم os.path.exists() ، here نص برمجي Python 3 يمكن استخدامه للتحقق من وجود دليل ، وإنشاء واحد إذا لم يكن موجودًا ، وحذفه إذا كان موجودًا (إذا رغبت في ذلك).

فإنه يطالب المستخدمين لإدخال الدليل ويمكن تعديلها بسهولة.


باستخدام المحاولة باستثناء رمز الخطأ الصحيح من الوحدة النمطية 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' مسبقاً وإزالة كافة الأذونات منه ، فسوف تحصل على OSError مرفوعًا errno.EACCES (تم رفض الإذن ، الخطأ 13).


بدءًا من Python 3.5 ، يحتوي exist_ok علامة 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 على علامة exists_ok تبدأ من python 3.2).


تقترح وثائق بايثون ذات الصلة استخدام أسلوب التشفير 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.path.exists

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

في Python3 ، يدعم exist_ok وضع exist_ok . الإعداد الافتراضي هو False ، مما يعني أنه سيتم رفع OSError إذا كان الدليل الهدف موجودًا بالفعل. بواسطة exist_ok إلى True ، سيتم تجاهل OSError (الدليل موجود) ولن يتم إنشاء الدليل.

os.makedirs(path,exist_ok=True)

في Python2 ، لا يدعم exist_ok وضع exist_ok . يمكنك استخدام النهج في الإجابة heikki-toivonen :

import os
import errno

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

في Python 3.4 ، يمكنك أيضًا استخدام وحدة pathlib الجديدة 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.

لقد وضعت التالي لأسفل. انها ليست مضمونة تماما رغم ذلك.

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

الآن كما أقول ، هذا ليس مضمونا حقاً ، لأننا نمتلك القدرة على الفشل في إنشاء الدليل ، وعملية أخرى تقوم بإنشائه خلال تلك الفترة.


للحصول على حل IPython.utils.path.ensure_dir_exists() الخطوط ، يمكنك استخدام IPython.utils.path.ensure_dir_exists() :

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

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


يمكنك استخدام os.listdir لهذا:

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

إذا كنت تفكر في ما يلي:

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

يعني وجود دليل (مسار) AND هو دليل. بالنسبة لي ، هذه الطريقة تفعل ما أحتاجه. حتى أتمكن من التأكد من أنه مجلد (وليس ملفًا) موجودًا.


عند العمل مع I / O ملف ، فإن الشيء المهم هو النظر

TOCTTOU (وقت الاختيار إلى وقت الاستخدام)

لذلك ، قد يؤدي إجراء عملية فحص ifثم القراءة أو الكتابة لاحقًا إلى استثناء I / O غير معالج. أفضل طريقة للقيام بذلك هي:

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

استدعاء الوظيفة 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"

حيث تستخدم شفرتك هنا أمر (اللمس)

سيتحقق هذا إذا كان الملف موجودًا إذا لم يكن موجودًا ، فسيعمل على إنشائه.





operating-system