Implement touch using Python?

Question:

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.)

Asked By: itsadok

||

Answers:

def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()
Answered By: SilentGhost

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.

Answered By: itsadok

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.

Answered By: itsadok

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)
Answered By: ephemient

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().

Answered By: jcoffland

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())
Answered By: eug

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.

Answered By: Manoj
with open(file_name,'a') as f: 
    pass
Answered By: Matt

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.

Answered By: voidnologo

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)
Answered By: oHo

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"])
Answered By: suresh Palemoni

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.

Answered By: Amar chand Dargad

write_text() from pathlib.Path can be used.

>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0
Answered By: SuperNova

For a more low-level solution one can use

os.close(os.open("file.txt", os.O_CREAT))
Answered By: heiner

There is also a python module for touch

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

You can install it with pip install touch

Answered By: GLNB
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.