501

touch is a Unix utility that sets the modification and access times of files to the current time of day. If the file doesn't exist, it is created with default permissions.

How would you implement it as a Python function? Try to be cross platform and complete.

(Current Google results for "python touch file" are not that great, but point to os.utime.)

itsadok
  • 28,822
  • 30
  • 126
  • 171
  • 7
    Please consider updating the accepted answer now that this functionality is built into the Python stdlib. – Miles Aug 17 '17 at 07:26
  • @Miles The accepted answer does exactly what the question asked for - it actually implemented the function in Python instead of using a library. – styrofoam fly Mar 05 '18 at 17:22
  • 10
    @styrofoamfly The standard library **is** part of Python. It's really likely that the what the question asker really wants to know (and most people arriving at this question via Google) is how to achieve `touch`-like functionality in their Python programs, not how to re-implement it from scratch; those people are best served by scrolling down to the `pathlib` solution. Even though it's now built-in, this answer has a much better Google ranking for "python touch file" than [the relevant documentation](https://docs.python.org/3/library/pathlib.html#pathlib.Path.touch). – Miles Mar 07 '18 at 04:50
  • 1
    @miles Python 2 is (unfortunately) still more widely used than 3, so I think the accepted answer is still the more relevant one. But your comment does a good job of pointing people to the second answer. – itsadok Mar 07 '18 at 12:02
  • 9
    Python 2 is EOL at the end of this year. – Max Gasner Feb 12 '19 at 00:29

16 Answers16

556

Looks like this is new as of Python 3.4 - pathlib.

from pathlib import Path

Path('path/to/file.txt').touch()

This will create a file.txt at the path.

--

Path.touch(mode=0o777, exist_ok=True)

Create a file at this given path. If mode is given, it is combined with the process’ umask value to determine the file mode and access flags. If the file already exists, the function succeeds if exist_ok is true (and its modification time is updated to the current time), otherwise FileExistsError is raised.

Honest Abe
  • 8,430
  • 4
  • 49
  • 64
voidnologo
  • 1,005
  • 2
  • 12
  • 14
  • 5
    On Python2.7: `pip install pathlib` – Andre Miras Oct 24 '17 at 17:54
  • 20
    note to self: use `Path('/some/path').mkdir()` if the directory containing the file to be `touch()`ed does not yet exist. – JacobIRR Jul 07 '18 at 05:04
  • 4
    I think we should use `pathlib2` instead of `pathlib` because `pathlib` is bugfix-only now. Therefore, on Python 2.7: `pip install pathlib2` and then `from pathlib2 import Path`. – Ian Lin Nov 23 '18 at 08:58
  • @IanLin There's little reason to install a library to do something that the standard library already supports. Are you confusing https://bitbucket.org/pitrou/pathlib/src/default/ with https://docs.python.org/dev/library/pathlib.html? – Michael Mrozek Mar 04 '20 at 22:40
  • That comment is replying Andre's comment talking about Python 2.7, which doesn't have that standard library. Feel free to read the document in https://pypi.org/project/pathlib2/ – Ian Lin Mar 06 '20 at 02:25
  • 3
    I'm surprised it defaults to `777` and not something more conservative like `644`. – zachaysan May 07 '20 at 18:49
  • 2
    I wanted to point out that `Path("...").touch()` returns nothing, so if you might want to store `Path("...")` to a variable before `.touch()`ing it. – Joe Sadoski Aug 25 '21 at 17:27
  • How does it differs from `open(fname, 'a').close()`? – alper Apr 03 '22 at 11:54
  • @zachaysan in Python 3 the default mode is 0664, and we can set that to a different value as well. can check [here](https://docs.python.org/3/library/pathlib.html#pathlib.Path.touch) – Shod Aug 12 '22 at 14:38
256

This tries to be a little more race-free than the other solutions. (The with keyword is new in Python 2.5.)

import os
def touch(fname, times=None):
    with open(fname, 'a'):
        os.utime(fname, times)

Roughly equivalent to this.

import os
def touch(fname, times=None):
    fhandle = open(fname, 'a')
    try:
        os.utime(fname, times)
    finally:
        fhandle.close()

Now, to really make it race-free, you need to use futimes and change the timestamp of the open filehandle, instead of opening the file and then changing the timestamp on the filename (which may have been renamed). Unfortunately, Python doesn't seem to provide a way to call futimes without going through ctypes or similar...


EDIT

As noted by Nate Parsons, Python 3.3 will add specifying a file descriptor (when os.supports_fd) to functions such as os.utime, which will use the futimes syscall instead of the utimes syscall under the hood. In other words:

import os
def touch(fname, mode=0o666, dir_fd=None, **kwargs):
    flags = os.O_CREAT | os.O_APPEND
    with os.fdopen(os.open(fname, flags=flags, mode=mode, dir_fd=dir_fd)) as f:
        os.utime(f.fileno() if os.utime in os.supports_fd else fname,
            dir_fd=None if os.supports_fd else dir_fd, **kwargs)
Community
  • 1
  • 1
ephemient
  • 198,619
  • 38
  • 280
  • 391
  • This is the real solution--and this is how touch(1) in coreutils does it, unless futimes() isn't available. futimes isn't a portable function and doesn't even exist on older 2.6 Linux kernels, so you need to deal with ENOSYS and fall back to utime even if you do use it. – Glenn Maynard Jul 21 '09 at 18:45
  • (Proofreading error above: "This" = open("a") + futimes.) Fortunately, it's hard to think of a case where the race condition of not using futimes actually matters. The "wrong" case you might end up with is the file being renamed between open() and utime(), in which case you'll neither create a new file nor touch the old one. That can matter, but most of the time it won't. – Glenn Maynard Jul 21 '09 at 18:52
  • cygwin touch can do its magic on read-only files, but this code cannot. However it seems to work if I surround it with try: except IOError as e: (check e.errno) os.utime(filename, times) – dash-tom-bang May 20 '11 at 02:09
  • FYI, it seems like futimes was added in 3.3 – Nate Parsons Aug 23 '12 at 16:36
  • Note: the built-in `file` function was removed from Python 3, and `open` has to be used instead. I totally missed this because the syntax highlighting of the editor I am using (gedit) is still targeting Python 2. – Bart Jan 24 '14 at 08:53
  • @AurélienOoms: Thanks, I was using documentation only (didn't have Python 3 installed) when this answer was originally written. Code has been updated to actually work now. – ephemient Oct 07 '14 at 08:35
  • Yes, it was not the only issue. I assume you have been able to test it now. – Mmmh mmh Oct 07 '14 at 08:37
  • This doesn't seem to work for a directory (unlike the Unix utility) - IOError: [Errno 21] Is a directory - how to fix this?? – jtlz2 May 13 '15 at 08:32
  • Can you explain how it is better than [@jcoffland's solution](http://stackoverflow.com/a/6222692/760767)? – Evpok Aug 07 '15 at 18:11
  • "open(file_name, 'a').close()" did not work for me in Python 2.7 on Windows. "os.utime(file_name, None)" worked just fine. – cadvena Jun 22 '16 at 21:16
  • What's the point of `None if os.supports_fd else dir_fd`? Why it is interesting to know whether `os.supports_fd` is empty or not? – Torsten Bronger Nov 14 '17 at 21:41
  • "open(file_name, 'a')" the "a" means what in this expression ? – pietà Apr 02 '18 at 16:49
  • Is there a way to do this in Python2 since there is no os.utime? I only know Python2, I read trying to learn Python2 and Python3 at the same time just makes things confusing and it's better to learn Python2 first. But perhaps I know enough Python 2 where that is no longer the case. – user324747 Mar 29 '20 at 16:42
49
def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()
Jens Timmerman
  • 9,316
  • 1
  • 42
  • 48
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
  • 9
    Agreed. Proper solution is just: def touch(fname): open(fname, 'wa').close() – stepancheg Jul 21 '09 at 10:25
  • @Greg, while it solves the potential racing condition issue, `open(fname, 'a').close()` won't change atime. – SilentGhost Jul 21 '09 at 10:40
  • @SilentGhost: That's true, but that's okay because if the file exists then it was *just* created. Of course you'd leave the call to `os.utime()` in there for pre-existing files. – Greg Hewgill Jul 21 '09 at 10:43
  • 4
    Why not just open to make sure it exists, then call utime? – itsadok Jul 21 '09 at 10:52
  • @itsadok: because it triggers another race condition: what if the file is _deleted_ between the `open()` and the `utime()` calls? IMHO a robust solution is the one presented [here](https://stackoverflow.com/a/6222692/624066) – MestreLion Feb 05 '21 at 09:05
37

Why not try this?:

import os

def touch(fname):
    try:
        os.utime(fname, None)
    except OSError:
        open(fname, 'a').close()

I believe this eliminates any race condition that matters. If the file does not exist then an exception will be thrown.

The only possible race condition here is if the file is created before open() is called but after os.utime(). But this does not matter because in this case the modification time will be as expected since it must have happened during the call to touch().

radtek
  • 34,210
  • 11
  • 144
  • 111
jcoffland
  • 5,238
  • 38
  • 43
22

For a more low-level solution one can use

os.close(os.open("file.txt", os.O_CREAT))
heiner
  • 598
  • 6
  • 11
19

This answer is compatible with all versions since Python-2.5 when keyword with has been released.

1. Create file if does not exist + Set current time
(exactly same as command touch)

import os

fname = 'directory/filename.txt'
with open(fname, 'a'):     # Create file if does not exist
    os.utime(fname, None)  # Set access/modified times to now
                           # May raise OSError if file does not exist

A more robust version:

import os

with open(fname, 'a'):
  try:                     # Whatever if file was already existing
    os.utime(fname, None)  # => Set current time anyway
  except OSError:
    pass  # File deleted between open() and os.utime() calls

2. Just create the file if does not exist
(does not update time)

with open(fname, 'a'):  # Create file if does not exist
    pass

3. Just update file access/modified times
(does not create file if not existing)

import os

try:
    os.utime(fname, None)  # Set access/modified times to now
except OSError:
    pass  # File does not exist (or no permission)

Using os.path.exists() does not simplify the code:

from __future__ import (absolute_import, division, print_function)
import os

if os.path.exists(fname):
  try:
    os.utime(fname, None)  # Set access/modified times to now
  except OSError:
    pass  # File deleted between exists() and utime() calls
          # (or no permission)

Bonus: Update time of all files in a directory

from __future__ import (absolute_import, division, print_function)
import os

number_of_files = 0

#   Current directory which is "walked through"
#   |     Directories in root
#   |     |  Files in root       Working directory
#   |     |  |                     |
for root, _, filenames in os.walk('.'):
  for fname in filenames:
    pathname = os.path.join(root, fname)
    try:
      os.utime(pathname, None)  # Set access/modified times to now
      number_of_files += 1
    except OSError as why:
      print('Cannot change time of %r because %r', pathname, why)

print('Changed time of %i files', number_of_files)
oHo
  • 51,447
  • 27
  • 165
  • 200
8

Here's some code that uses ctypes (only tested on Linux):

from ctypes import *
libc = CDLL("libc.so.6")

#  struct timespec {
#             time_t tv_sec;        /* seconds */
#             long   tv_nsec;       /* nanoseconds */
#         };
# int futimens(int fd, const struct timespec times[2]);

class c_timespec(Structure):
    _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]

class c_utimbuf(Structure):
    _fields_ = [('atime', c_timespec), ('mtime', c_timespec)]

utimens = CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))
futimens = CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf)) 

# from /usr/include/i386-linux-gnu/bits/stat.h
UTIME_NOW  = ((1l << 30) - 1l)
UTIME_OMIT = ((1l << 30) - 2l)
now  = c_timespec(0,UTIME_NOW)
omit = c_timespec(0,UTIME_OMIT)

# wrappers
def update_atime(fileno):
        assert(isinstance(fileno, int))
        libc.futimens(fileno, byref(c_utimbuf(now, omit)))
def update_mtime(fileno):
        assert(isinstance(fileno, int))
        libc.futimens(fileno, byref(c_utimbuf(omit, now)))

# usage example:
#
# f = open("/tmp/test")
# update_mtime(f.fileno())
eug
  • 1,118
  • 1
  • 16
  • 25
  • Did you benchmark this? I heard that the boundary between CPython and C is slow with ctypes. EG I heard that pygame was modified to use ctypes, but it was so much slower the project was abandoned. – dstromberg Nov 22 '22 at 03:56
6

Simplistic:

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • The open ensures there is a file there
  • the utime ensures that the timestamps are updated

Theoretically, it's possible someone will delete the file after the open, causing utime to raise an exception. But arguably that's OK, since something bad did happen.

itsadok
  • 28,822
  • 30
  • 126
  • 171
5
with open(file_name,'a') as f: 
    pass
Matt
  • 3,483
  • 4
  • 36
  • 46
  • 1
    **Fail**: `with open(fn,'a'): pass` or alternative `open(fn, 'a').close()` do not change the modified time using Python 2.7.5 on Red Hat 7 (filesystem is XFS). On my platform, these solutions just create an empty file if does not exist. :-/ – oHo Jun 06 '17 at 13:58
4

The following is sufficient:

import os
def func(filename):
    if os.path.exists(filename):
        os.utime(filename)
    else:
        with open(filename,'a') as f:
            pass

If you want to set a specific time for touch, use os.utime as follows:

os.utime(filename,(atime,mtime))

Here, atime and mtime both should be int/float and should be equal to epoch time in seconds to the time which you want to set.

2

Complex (possibly buggy):

def utime(fname, atime=None, mtime=None)
    if type(atime) is tuple:
        atime, mtime = atime

    if atime is None or mtime is None:
        statinfo = os.stat(fname)
        if atime is None:
            atime = statinfo.st_atime
        if mtime is None:
            mtime = statinfo.st_mtime

    os.utime(fname, (atime, mtime))


def touch(fname, atime=None, mtime=None):
    if type(atime) is tuple:
        atime, mtime = atime

    open(fname, 'a').close()
    utime(fname, atime, mtime)

This tries to also allow setting the access or modification time, like GNU touch.

itsadok
  • 28,822
  • 30
  • 126
  • 171
1

It might seem logical to create a string with the desired variables, and pass it to os.system:

touch = 'touch ' + dir + '/' + fileName
os.system(touch)

This is inadequate in a number of ways (e.g.,it doesn't handle whitespace), so don't do it.

A more robust method is to use subprocess :

subprocess.call(['touch', os.path.join(dirname, fileName)])

While this is much better than using a subshell (with os.system), it is still only suitable for quick-and-dirty scripts; use the accepted answer for cross-platform programs.

belacqua
  • 543
  • 4
  • 18
Manoj
  • 1
  • 1
  • This isn't very safe: what happens when there is a space in the filename? – ayke Jul 08 '12 at 10:54
  • 5
    `subprocess.call(['touch', os.path.join(dirname, fileName)])` is much better than using a subshell (with `os.system`). But still, use this only for quick-and-dirty scripts, use the accepted answer for cross-platform programs. – ayke Jul 08 '12 at 10:58
  • 1
    `touch` is not a cross-platform available command (e.g. Windows) – Mike T May 21 '18 at 06:23
1

write_text() from pathlib.Path can be used.

>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0
SuperNova
  • 25,512
  • 7
  • 93
  • 64
0

Why don't you try: newfile.py

#!/usr/bin/env python
import sys
inputfile = sys.argv[1]

with open(inputfile, 'r+') as file:
    pass

python newfile.py foobar.txt

or

use subprocess:

import subprocess
subprocess.call(["touch", "barfoo.txt"])
Bachsau
  • 1,213
  • 14
  • 21
suresh Palemoni
  • 1,138
  • 14
  • 12
0

There is also a python module for touch

>>> from touch import touch
>>> touch(file_name)

You can install it with pip install touch

GLNB
  • 61
  • 5
0

I have a program that I use for backups: https://stromberg.dnsalias.org/~strombrg/backshift/

I profiled it using vmprof, and identified that touch was by far the most time-consuming part of it.

So I looked into ways of touching files quickly.

I found that on CPython 3.11, this was the fastest:

def touch3(filename, flags=os.O_CREAT | os.O_RDWR):                                                                                  
    """Touch a file using os.open+os.close - fastest on CPython 3.11."""                                                             
    os.close(os.open(filename, flags, 0o644))    

                                                                                

And on Pypy3 7.3.9, this was the fastest:

def touch1(filename):                                                                                                                
    """Touch a file using pathlib - fastest on pypy3, and fastest overall."""                                                        
    Path(filename).touch()                                                                                                           

Of the two, pypy3's best was only slightly faster cpython's best.

I may create a web page about this someday, but for now all I have is a Subversion repo: https://stromberg.dnsalias.org/svn/touch/trunk It includes the 4 ways of doing touches I tried.

dstromberg
  • 6,954
  • 1
  • 26
  • 27