515

Say I want to make a file:

filename = "/foo/bar/baz.txt"

with open(filename, "w") as f:
    f.write("FOOBAR")

This gives an IOError, since /foo/bar does not exist.

What is the most pythonic way to generate those directories automatically? Is it necessary for me explicitly call os.path.exists and os.mkdir on every single one (i.e., /foo, then /foo/bar)?

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Phil
  • 6,686
  • 2
  • 19
  • 25

1 Answers1

970

In Python 3.2+, using the APIs requested by the OP, you can elegantly do the following:


import os

filename = "/foo/bar/baz.txt"
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, "w") as f:
    f.write("FOOBAR")


With the Pathlib module (introduced in Python 3.4), there is an alternate syntax (thanks David258):

from pathlib import Path
output_file = Path("/foo/bar/baz.txt")
output_file.parent.mkdir(exist_ok=True, parents=True)
output_file.write_text("FOOBAR")

In older python, there is a less elegant way:

The os.makedirs function does this. Try the following:

import os
import errno

filename = "/foo/bar/baz.txt"
if not os.path.exists(os.path.dirname(filename)):
    try:
        os.makedirs(os.path.dirname(filename))
    except OSError as exc: # Guard against race condition
        if exc.errno != errno.EEXIST:
            raise

with open(filename, "w") as f:
    f.write("FOOBAR")

The reason to add the try-except block is to handle the case when the directory was created between the os.path.exists and the os.makedirs calls, so that to protect us from race conditions.


Krumelur
  • 31,081
  • 7
  • 77
  • 119
  • 2
    Just had to look past `os.mkdir` and read the documentation on one more function :) – mgilson Sep 20 '12 at 17:09
  • 9
    There is a slightly different approach here: http://stackoverflow.com/a/14364249/1317713 Thoughts? – Leonid Apr 11 '16 at 06:02
  • 2
    Is the inital `if not os.path.exists` needed since the `os.makedirs` uses [EAFP](https://docs.python.org/2/glossary.html#term-eafp)? – Marcel Wilson Aug 16 '17 at 16:37
  • 2
    nice. but be aware you may need to check that the filename contains a path or attempting to create a path with an empty name (eg derived from `baz.txt`) will error `FileNotFoundError: [Errno 2] No such file or directory: ''` Obviously, this will only happen if you are writing into the present working directory. – ErichBSchulz Aug 06 '18 at 00:52
  • 3
    PermissionError: [Errno 13] Permission denied: '/foo' – Ka Wa Yip Aug 17 '18 at 11:05
  • 1
    @Ka-WaYip `/foo/bar/baz.txt` is just an example. Replace it with the path you wish your file to be created. In linux, the command `pwd` gives you the path to the current working directory. – LoMaPh Sep 16 '19 at 16:55
  • 11
    with Pathlib: `from pathlib import Path; output_file = Path("/foo/bar/baz.txt"); output_file.parent.mkdir(exist_ok=True, parents=True); output_file.write_text("FOOBAR")` – David258 Jan 12 '21 at 12:46
  • @David258 Sorry they closed this question so you don't get any karma for your comment that's more useful now than the actual answer. But thanks. – Noumenon Sep 05 '21 at 16:26