วิธีใดที่หรูหราที่สุดในการตรวจสอบว่าไดเร็กทอรีที่ไฟล์จะถูกเขียนมีอยู่จริงหรือไม่ และถ้าไม่ใช่ ให้สร้างไดเร็กทอรีโดยใช้ 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(ขอบคุณคันจา แบลร์ และดักลาส) นี่คือสิ่งที่ฉันมีตอนนี้:

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

มีแฟล็กสำหรับ "เปิด" ที่ทำให้สิ่งนี้เกิดขึ้นโดยอัตโนมัติหรือไม่?

ตอบ

บน Python ≥ 3.5 ให้ใช้pathlib.Path.mkdir:

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

สำหรับ Python เวอร์ชันเก่า ฉันเห็นคำตอบสองข้อที่มีคุณสมบัติที่ดี แต่ละคำตอบมีข้อบกพร่องเล็กน้อย ดังนั้นฉันจะลองดู:

ลองos.path.existsและพิจารณาos.makedirsสำหรับการสร้าง

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

ตามที่ระบุไว้ในความคิดเห็นและที่อื่นๆ มีเงื่อนไขการแข่งขัน – หากไดเรกทอรีถูกสร้างขึ้นระหว่างos.path.existsการos.makedirsเรียกและการเรียกos.makedirsจะล้มเหลวด้วย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แต่สมมติว่าไดเรกทอรีอื่นสร้างไดเร็กทอรีหลังจากการตรวจสอบครั้งแรก จากนั้นจึงลบออกก่อนไดเร็กทอรีที่สอง เราอาจถูกหลอกได้

อันตรายจากการทำงานพร้อมกันอาจมากหรือน้อยกว่าอันตรายที่เกิดจากปัจจัยอื่นๆ เช่น การอนุญาตไฟล์ ทั้งนี้ขึ้นอยู่กับแอปพลิเคชัน นักพัฒนาจะต้องทราบข้อมูลเพิ่มเติมเกี่ยวกับแอปพลิเคชันเฉพาะที่กำลังพัฒนาและสภาพแวดล้อมที่คาดหวังก่อนที่จะเลือกการใช้งาน

Python เวอร์ชันใหม่ปรับปรุงโค้ดนี้เล็กน้อย ทั้งโดยการเปิดเผยFileExistsError(ใน 3.3+)...

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

...และโดยอนุญาตให้เรียกอาร์กิวเมนต์คำหลักos.makedirsexist_ok (ใน 3.2+)

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

หลาม 3.5+:

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

pathlib.Path.mkdirตามที่ใช้ข้างต้นจะสร้างไดเร็กทอรีซ้ำ ๆ และไม่ทำให้เกิดข้อยกเว้นหากมีไดเร็กทอรีอยู่แล้ว หากคุณไม่ต้องการหรือต้องการให้ผู้ปกครองถูกสร้างขึ้น ให้ข้ามparentsอาร์กิวเมนต์

หลาม 3.2+:

การใช้pathlib:

หากทำได้ ให้ติดตั้งpathlibbackport ปัจจุบันที่ชื่อpathlib2. อย่าติดตั้ง backport ที่เก่ากว่าที่ชื่อpathlib. ถัดไป อ้างถึงส่วน Python 3.5+ ด้านบนและใช้งานแบบเดียวกัน

หากใช้ Python 3.4 แม้ว่าจะมาพร้อมกับpathlibก็ยังไม่มีexist_okตัวเลือกที่มีประโยชน์ แบ็คพอร์ตมีวัตถุประสงค์เพื่อเสนอการใช้งานที่ใหม่กว่าและเหนือกว่าmkdirซึ่งรวมถึงตัวเลือกที่ขาดหายไปนี้

การใช้os:

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

os.makedirsตามที่ใช้ข้างต้นจะสร้างไดเร็กทอรีซ้ำ ๆ และไม่ทำให้เกิดข้อยกเว้นหากมีไดเร็กทอรีอยู่แล้ว มีexist_okอาร์กิวเมนต์ที่เป็นทางเลือกก็ต่อเมื่อใช้ Python 3.2+ โดยมีค่าเริ่มต้นเป็นFalse. อาร์กิวเมนต์นี้ไม่มีอยู่ใน Python 2.x สูงถึง 2.7 ดังนั้นจึงไม่จำเป็นต้องมีการจัดการข้อยกเว้นด้วยตนเองเช่นเดียวกับ Python 2.7

หลาม 2.7+:

การใช้pathlib:

หากทำได้ ให้ติดตั้งpathlibbackport ปัจจุบันที่ชื่อpathlib2. อย่าติดตั้ง backport ที่เก่ากว่าที่ชื่อ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โซลูชันด้านบนจะกลับลำดับของการดำเนินการทั้งสอง ในการทำเช่นนั้น จะป้องกันสภาวะการแข่งขันทั่วไปที่เกี่ยวข้องกับความพยายามสร้างไดเร็กทอรีที่ซ้ำกัน และยังแก้ความกำกวมไฟล์จากไดเร็กทอรี

โปรดทราบว่าการดักจับข้อยกเว้นและการใช้errnoนั้นมีประโยชน์จำกัด เนื่องจากOSError: [Errno 17] File existsกล่าวerrno.EEXISTคือ ถูกยกขึ้นสำหรับทั้งไฟล์และไดเร็กทอรี เชื่อถือได้มากกว่าเพียงแค่ตรวจสอบว่ามีไดเร็กทอรีอยู่หรือไม่

ทางเลือก:

mkpathสร้างไดเร็กทอรีที่ซ้อนกัน และไม่ทำอะไรเลยหากไดเร็กทอรีมีอยู่แล้ว ใช้งานได้ทั้งใน Python 2 และ 3

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

ตามข้อบกพร่อง 10948ข้อ จำกัด ที่รุนแรงของทางเลือกนี้คือใช้งานได้เพียงครั้งเดียวต่อกระบวนการ python สำหรับเส้นทางที่กำหนด กล่าวอีกนัยหนึ่ง ถ้าคุณใช้เพื่อสร้างไดเร็กทอรี ให้ลบไดเร็กทอรีจากภายในหรือภายนอก Python จากนั้นใช้mkpathอีกครั้งเพื่อสร้างไดเร็กทอรีเดียวกันใหม่mkpathจะใช้ข้อมูลแคชที่ไม่ถูกต้องของการสร้างไดเร็กทอรีก่อนหน้านี้อย่างเงียบๆ และจะไม่ จริง ๆ แล้วสร้างไดเร็กทอรีอีกครั้ง ในทางตรงกันข้ามos.makedirsไม่พึ่งพาแคชดังกล่าว ข้อจำกัดนี้อาจใช้ได้สำหรับบางแอปพลิเคชัน


สำหรับโหมดของไดเรกทอรีโปรดดูเอกสารประกอบหากคุณสนใจ

การใช้ลองยกเว้นและรหัสข้อผิดพลาดที่ถูกต้องจากโมดูล 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)

โดยส่วนตัวแล้วฉันจะแนะนำให้คุณใช้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

... คุณจะจบลงด้วยไดเร็กทอรีที่ตั้งชื่อfilename.etcเมื่อคุณส่งอาร์กิวเมนต์นั้นos.makedirs()หากคุณทดสอบด้วยos.path.exists().

เริ่มต้นจาก 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การexist_okตั้งค่าสถานะเริ่มต้นจาก python 3.2 เช่นos.makedirs(path, exist_ok=True))


หมายเหตุ: เมื่อฉันโพสต์คำตอบนี้ไม่มีคำตอบอื่นใดที่กล่าวถึงexist_ok...

ตรวจสอบos.makedirs: (. มันทำให้แน่ใจว่าเส้นทางที่สมบูรณ์มี) เพื่อจัดการกับความจริงที่ไดเรกทอรีอาจจะมีอยู่จับ
OSError(ถ้าexist_okเป็นFalse(ค่าดีฟอลต์) an OSErrorจะเพิ่มขึ้นหากไดเร็กทอรีเป้าหมายมีอยู่แล้ว)

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

ข้อมูลเชิงลึกเกี่ยวกับสถานการณ์เฉพาะนี้

คุณให้ไฟล์เฉพาะที่เส้นทางที่แน่นอน และคุณดึงไดเร็กทอรีจากพาธของไฟล์ หลังจากตรวจสอบให้แน่ใจว่าคุณมีไดเร็กทอรีแล้ว คุณพยายามเปิดไฟล์เพื่ออ่าน หากต้องการแสดงความคิดเห็นเกี่ยวกับรหัสนี้:

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โหมด (หรือ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สายในบล็อกการยกเว้น

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ฟังก์ชั่น

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

ฉันได้วางสิ่งต่อไปนี้ลง มันไม่สามารถเข้าใจผิดได้ทั้งหมด

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

อย่างที่ฉันพูด นี่ไม่ใช่วิธีที่จะเข้าใจผิดได้ เพราะเรามีความเป็นไปได้ที่จะสร้างไดเร็กทอรีล้มเหลว และกระบวนการอื่นที่สร้างไดเร็กทอรีในช่วงเวลานั้น

Check if a directory exists and create it if necessary?

คำตอบโดยตรงสำหรับสิ่งนี้คือ สมมติว่าเป็นสถานการณ์ง่ายๆ ที่คุณไม่ได้คาดหวังให้ผู้ใช้หรือกระบวนการอื่นมายุ่งกับไดเรกทอรีของคุณ:

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.Pathด้วยexist_ok

มีPathอ็อบเจ็กต์ใหม่(ณ 3.4) ที่มีเมธอดมากมายที่เราต้องการใช้กับพาธ ซึ่งหนึ่งในนั้นคือmkdir.

(สำหรับบริบท ฉันกำลังติดตามตัวแทนรายสัปดาห์ของฉันด้วยสคริปต์ นี่คือส่วนที่เกี่ยวข้องของโค้ดจากสคริปต์ที่ช่วยให้ฉันหลีกเลี่ยงการกดปุ่ม Stack Overflow มากกว่าวันละครั้งสำหรับข้อมูลเดียวกัน)

ขั้นแรกให้นำเข้าที่เกี่ยวข้อง:

from pathlib import Path
import tempfile

เราไม่ต้องจัดการกับos.path.joinตอนนี้ - เพียงเข้าร่วมส่วนเส้นทางด้วย/:

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

จากนั้นฉันก็แน่ใจว่ามีไดเร็กทอรีอยู่ - exist_okอาร์กิวเมนต์แสดงใน Python 3.5:

directory.mkdir(exist_ok=True)

นี่คือส่วนที่เกี่ยวข้องของเอกสารประกอบ :

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.

นี่เป็นสคริปต์เพิ่มเติมเล็กน้อย - ในกรณีของฉัน ฉันไม่ได้อยู่ภายใต้เงื่อนไขการแข่งขัน ฉันมีกระบวนการเดียวที่คาดว่าไดเรกทอรี (หรือไฟล์ที่มีอยู่) จะอยู่ที่นั่น และฉันไม่มีอะไรพยายามลบ ไดเร็กทอรี

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ก่อนที่ API อื่นๆ ที่คาดว่าพาธstrจะใช้งานได้

บางทีควรอัปเดต Pandas ให้ยอมรับอินสแตนซ์ของคลาสพื้นฐานที่เป็นนามธรรมos.PathLike.

ใน 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.

สำหรับโซลูชันแบบซับเดียว คุณสามารถใช้IPython.utils.path.ensure_dir_exists():

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

จากเอกสารประกอบ : ตรวจสอบให้แน่ใจว่ามีไดเร็กทอรีอยู่ หากไม่มีอยู่ ให้พยายามสร้างและป้องกันสภาพการแข่งขันหากกระบวนการอื่นทำเช่นเดียวกัน

IPython เป็นแพ็คเกจส่วนขยาย ไม่ใช่ส่วนหนึ่งของไลบรารีมาตรฐาน

ในPython3 , สนับสนุนการตั้งค่าos.makedirs exist_okการตั้งค่าเริ่มต้นคือFalseซึ่งหมายความว่าOSErrorจะเพิ่มขึ้นหากไดเรกทอรีเป้าหมายมีอยู่แล้ว โดยการตั้งค่าexist_okเป็นTrue, OSError(ไดเร็กทอรีที่มีอยู่) จะถูกละเว้นและจะไม่สร้างไดเร็กทอรี

os.makedirs(path,exist_ok=True)

ในPython2 , ไม่สนับสนุนการตั้งค่าos.makedirs 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

เอกสารหลามที่เกี่ยวข้องแสดงให้เห็นการใช้งานของรูปแบบการเข้ารหัส 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

เอกสารประกอบแนะนำสิ่งนี้อย่างแน่นอนเนื่องจากสภาพการแข่งขันที่กล่าวถึงในคำถามนี้ นอกจากนี้ ตามที่คนอื่น ๆ กล่าวถึงที่นี่ มีความได้เปรียบด้านประสิทธิภาพในการสืบค้นหนึ่งครั้งแทนที่จะเป็นสองเท่าของระบบปฏิบัติการ สุดท้าย อาร์กิวเมนต์ที่วางไว้ข้างหน้าอาจสนับสนุนโค้ดที่สองในบางกรณี -- เมื่อนักพัฒนาทราบสภาพแวดล้อมที่แอปพลิเคชันกำลังทำงานอยู่ - สามารถสนับสนุนได้เฉพาะในกรณีพิเศษที่โปรแกรมได้ตั้งค่าสภาพแวดล้อมส่วนตัวสำหรับ ตัวเอง (และอินสแตนซ์อื่นๆ ของโปรแกรมเดียวกัน)

แม้แต่ในกรณีนั้น นี่เป็นแนวปฏิบัติที่ไม่ดีและอาจนำไปสู่การดีบักที่ไร้ประโยชน์เป็นเวลานาน ตัวอย่างเช่น การที่เราตั้งค่าการอนุญาตสำหรับไดเร็กทอรีไม่ควรปล่อยให้เรามีการอนุญาตอิมเพรสชั่นที่เหมาะสมกับวัตถุประสงค์ของเรา สามารถติดตั้งไดเร็กทอรีหลักด้วยการอนุญาตอื่น โดยทั่วไป โปรแกรมควรทำงานอย่างถูกต้องเสมอ และโปรแกรมเมอร์ไม่ควรคาดหวังสภาพแวดล้อมเฉพาะอย่างใดอย่างหนึ่ง

คุณสามารถใช้ได้ 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

ฉันพบคำถาม/คำตอบนี้ และในตอนแรกฉันรู้สึกสับสนกับความล้มเหลวและข้อผิดพลาดบางอย่างที่ฉันได้รับ ฉันทำงานใน Python 3 (v.3.5 ในสภาพแวดล้อมเสมือน Anaconda บนระบบ Arch Linux x86_64)

พิจารณาโครงสร้างไดเรกทอรีนี้:

└── 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

ผมใช้os.path.exists(), ที่นี่เป็นสคริปต์ Python 3 ที่สามารถใช้เพื่อตรวจสอบว่าไดเรกทอรีที่มีอยู่สร้างหนึ่งถ้ามันไม่ได้อยู่และลบมันถ้ามันไม่อยู่ (ถ้าต้องการ)

จะแจ้งให้ผู้ใช้ป้อนข้อมูลของไดเร็กทอรีและสามารถแก้ไขได้ง่าย

ใช้คำสั่งตรวจสอบและสร้าง dir

 if not os.path.isdir(test_img_dir):
     os.mkdir(test_img_dir)

ทำไมไม่ใช้ subprocess module ถ้าทำงานบนเครื่องที่รองรับ command mkdirwith -poption? ทำงานบน python 2.7 และ python 3.6

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

ควรทำเคล็ดลับกับระบบส่วนใหญ่

ในสถานการณ์ที่การพกพาไม่สำคัญ (เช่น การใช้นักเทียบท่า) วิธีแก้ปัญหาคือ 2 บรรทัด คุณไม่จำเป็นต้องเพิ่มตรรกะเพื่อตรวจสอบว่ามีไดเรกทอรีอยู่หรือไม่ สุดท้ายก็วิ่งซ้ำได้อย่างปลอดภัยโดยไม่มีผลข้างเคียง

หากคุณต้องการจัดการข้อผิดพลาด:

from subprocess import check_call
try:
    check_call(['mkdir', '-p', 'path1/path2/path3'])
except:
    handle...

ฉันเห็นคำตอบของHeikki ToivonenและABBและคิดถึงรูปแบบนี้

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

คุณต้องตั้งค่าพาธแบบเต็มก่อนสร้างไดเร็กทอรี:

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)

สิ่งนี้ใช้ได้สำหรับฉันและหวังว่าจะได้ผลสำหรับคุณเช่นกัน

คุณสามารถใช้os.listdirสำหรับสิ่งนี้:

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

เรียกใช้ฟังก์ชัน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')

หากคุณพิจารณาสิ่งต่อไปนี้:

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

หมายถึงไดเร็กทอรี (เส้นทาง) ที่มีอยู่และคือไดเร็กทอรี ดังนั้นสำหรับฉัน วิธีนี้คือสิ่งที่ฉันต้องการ ดังนั้นฉันจึงมั่นใจได้ว่าเป็นโฟลเดอร์ (ไม่ใช่ไฟล์) และมีอยู่จริง

คุณสามารถสร้างไฟล์และไดเร็กทอรีพาเรนต์ทั้งหมดใน 1 คำสั่งพร้อมfastcoreนามสกุลเป็น pathlib:path.mk_write(data)

from fastcore.utils import Path
Path('/dir/to/file.txt').mk_write('Hello World')

ดูเพิ่มเติมในเอกสารประกอบ fastcore

ในกรณีที่คุณกำลังเขียนไฟล์ไปยังพาธตัวแปร คุณสามารถใช้สิ่งนี้บนพาธของไฟล์เพื่อให้แน่ใจว่าไดเร็กทอรีหลักถูกสร้างขึ้น

from pathlib import Path

path_to_file = Path("zero/or/more/directories/file.ext")
parent_directory_of_file = path_to_file.parent
parent_directory_of_file.mkdir(parents=True, exist_ok=True)

ทำงานได้แม้ว่าpath_to_fileจะเป็นfile.ext(ศูนย์ไดเรกทอรีลึก)

ดูpathlib.PurePath.parentและpathlib.Path.mkdir

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

Where your code here is use the (touch) command

วิธีนี้จะตรวจสอบว่ามีไฟล์อยู่หรือไม่ ถ้าไม่ใช่ ไฟล์จะสร้างขึ้นมา

ภายใต้ Linux คุณสามารถสร้างไดเร็กทอรีในบรรทัดเดียว:

import os
os.system("mkdir -p {0}".format('mydir'))