325

I'd like to create a file with path x using python. I've been using os.system(y) where y = 'touch %s' % (x). I've looked for a non-directory version of os.mkdir, but I haven't been able to find anything. Is there a tool like this to create a file without opening it, or using system or popen/subprocess?

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
tkbx
  • 15,602
  • 32
  • 87
  • 122
  • @LevLevitsky because I'd have to close it again :P. I have to create thousands of files, and just touching the file seems cleaner. – tkbx Sep 29 '12 at 17:26
  • 1
    FYI, while using an external command for this is always bad, the proper way to execute it would be `subprocess.call(['touch', x])` – ThiefMaster Sep 29 '12 at 17:31
  • 5
    @tkbx: "clean" can mean many things to many people. For example, spawning a completely separate process thousands of times is not very clean in my opinion. Sure, on modern OS's running on modern hardware a new process can be spawned pretty quickly, but it's still a crazy amount of overhead for such a small thing. – Bryan Oakley Sep 29 '12 at 17:33
  • @BryanOakley to describe emotions the best way I can, "clean" to me is the program being "truly finished", with no possibility for error. `print(x); os.mkdir(y), zint = int(z)` would be a very "clean" program in my opinion, because it's all functions that preform their task with no room for error or overhead. Something like `os.touch()` would seem "clean" to me, because however many thousands of times it runs, the workflow is the same, and it even if the script takes a year, I know the code has fulfilled it's purpose without any error margin by the end. – tkbx Sep 29 '12 at 18:04
  • 7
    How do you think `touch` does its job? http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/touch.c?id=f2ef324811cef997a7a7f41c895d2fc8febfb2c7 line 134 – msw Aug 02 '15 at 16:22
  • what about `Path(path2file).expanduser().touch()` – Charlie Parker Jun 17 '22 at 18:03

2 Answers2

569

There is no way to create a file without opening it There is os.mknod("newfile.txt") (but it requires root privileges on OSX). The system call to create a file is actually open() with the O_CREAT flag. So no matter how, you'll always open the file.

So the easiest way to simply create a file without truncating it in case it exists is this:

open(x, 'a').close()

Actually you could omit the .close() since the refcounting GC of CPython will close it immediately after the open() statement finished - but it's cleaner to do it explicitely and relying on CPython-specific behaviour is not good either.

In case you want touch's behaviour (i.e. update the mtime in case the file exists):

import os
def touch(path):
    with open(path, 'a'):
        os.utime(path, None)

You could extend this to also create any directories in the path that do not exist:

basedir = os.path.dirname(path)
if not os.path.exists(basedir):
    os.makedirs(basedir)
ccpizza
  • 28,968
  • 18
  • 162
  • 169
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • Looks good... "Truncate" is essentially "clear", right? – tkbx Sep 29 '12 at 17:26
  • 7
    Yes, opening a file with the `w` (write) flag empties it while opening it with `a` (append) doesn't. – ThiefMaster Sep 29 '12 at 17:27
  • 28
    Refcounting closing the file immediate is not to be relied on. This is not a matter of cleanliness, as refcounting is just an implementation detail. No Python except CPython does it. Want to make your program five times faster with PyPy, or run it in a Java/.NET environment with Jython/IronPython? Well too bad you didn't close those files, now your program is leaking like a sieve ;) It's especially awful since 2.5, as `with` makes it *easier* to close the file timely (and even in the face of exceptions and circular references) **and** the code becomes clearer to boot. –  Sep 29 '12 at 19:16
  • 5
    @ThiefMaster Wouldn't it be better not to talk about specific behavior of CPython in all cases where the question doesn't mention this concrete implementation? :) – Piotr Dobrogost Sep 29 '12 at 19:59
  • 2
    Moreover, most of the people we need to persuade not to do this either don't know what CPython is, or foolishly assume it's the only Python that matters. I saw the reference to CPython, but the entire sentence wasn't preachy enough for my taste :) –  Sep 29 '12 at 20:27
  • I wanted to overwrite a file with nothing even if it existed: `open(myfile, 'w').close()` – TheWalkingData Feb 21 '17 at 20:42
  • 11
    A better one-liner is probably `with open(filename, mode='a'): pass` – Nick T May 29 '19 at 16:55
  • Note that a minor optimization (that removes a race condition) is to pass the file descriptor from the file you opened to `os.utime`. Just change `with open(path, 'a'): os.utime(path, None)` (and that `None` argument wasn't needed; it's set by default) to `with open(path, 'a') as f: os.utime(f.fileno())` (if you need portability, you'd have to test `if os.utime in os.supports_follow_symlinks:` and only pass the file number if that returns true). This feature relies on Python 3.3, just to be clear. – ShadowRanger Jun 20 '19 at 18:52
  • 2
    In Python 3.3 the 'x' mode was added: "open for exclusive creation, failing if the file already exists" https://docs.python.org/3/library/functions.html#open – sunyata Dec 25 '19 at 21:53
60

Of course there IS a way to create files without opening. It's as easy as calling os.mknod("newfile.txt"). The only drawback is that this call requires root privileges on OSX.

Dave
  • 7,555
  • 8
  • 46
  • 88
Bachsau
  • 1,213
  • 14
  • 21
  • 1
    Great point. See also https://docs.python.org/3/library/os.html – poolie Aug 02 '15 at 15:37
  • 36
    it's also unix-only. Won't work on windows – Jean-François Fabre Aug 13 '18 at 22:01
  • 1
    It is the only way if you absolutely want to avoid opening the file, even though it's primary use-case is to create device files and things like that, which is probably the reason why it requires root privileges on some systems. For compatibility reasons I would always stick to the `open().close()` approach wherever possible. – Bachsau Sep 29 '19 at 15:09
  • @CharlieParker Because opening for writing is the way to create a file right down to the operating system's API. `pathlib` and the path-like objects are a fairly recent addition to Python and absolutely superfluous in my opinion (like most features introduced after 3.6), but yes, that will work. However, if you look at the source code, you will find that it also just calls `os.open()` followed by `os.close()` to do the deed. – Bachsau Jun 18 '22 at 19:47