Implémenter touch en utilisant Python?

touch est un utilitaire Unix qui définit les temps de modification et d'accès des fichiers à l'heure courante de la journée. Si le fichier n'existe pas, il est créé avec les permissions par défaut.

comment l'implémentez-vous comme une fonction Python? Essayez d'être multi-plateforme et complète.

(les résultats Google actuels pour" Python touch file "ne sont pas si bons, mais pointent vers os.utime .)

236
demandé sur itsadok 2009-07-21 13:05:11

11 réponses

cela essaie d'être un peu plus libre que les autres solutions. (Le mot-clé with est nouveau en Python 2.5.)

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

à peu près équivalent à ceci.

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

maintenant, pour vraiment le rendre sans course, vous devez utiliser futimes et changer l'horodatage du fichier ouvert, au lieu d'ouvrir le fichier et de changer l'horodatage sur le nom du fichier (qui peut avoir été renommé). Malheureusement, Python ne semble pas fournir une façon d'appeler futimes sans passer par ctypes ou similaire...


modifier

comme noté par Nate Parsons , Python 3.3 ajouter spécifiant un descripteur de fichier (lorsque os.supports_fd ) à des fonctions telles que os.utime , qui utilisera le futimes syscall au lieu du utimes syscall sous la hotte. En d'autres termes:

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)
218
répondu ephemient 2017-05-23 11:33:26

on dirait que C'est nouveau depuis Python 3.4 - pathlib .

from pathlib import Path

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

cela créera un file.txt sur le chemin.

--

Chemin d'accès.touch (mode=0o777, exist_ok=True)

crée un fichier à ce chemin donné. Si le mode est donné, il est combiné avec la valeur umask du processus pour déterminer le mode de fichier et les options d'accès. Si le fichier existe déjà, la fonction réussit si exist_ok est true (et son temps de modification est mis à jour à l'heure actuelle), sinon FileExistsError est soulevé.

128
répondu voidnologo 2016-10-22 16:16:42
def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()
34
répondu SilentGhost 2014-02-21 14:01:28

pourquoi ne pas essayer ceci?:

import os

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

je crois que cela élimine toute condition de race qui importe. Si le fichier n'existe pas, une exception sera levée.

la seule condition possible ici est que le fichier soit créé avant que open() soit appelé mais après os.utime (). Mais cela n'a pas d'importance parce que dans ce cas le temps de modification sera comme prévu puisqu'il doit s'être produit pendant l'appel à touch().

25
répondu jcoffland 2017-01-18 16:16:55

voici du code qui utilise des ctypes (testés uniquement sur 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())
8
répondu eug 2012-01-14 07:44:18

Simpliste:

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • le open assure qu'il y a un fichier
  • le utime assure la mise à jour des horodateurs

théoriquement, il est possible que quelqu'un supprime le fichier après le open , provoquant utime de soulever une exception. Mais ce N'est pas grave, puisque quelque chose de mal est arrivé.

3
répondu itsadok 2009-07-21 14:08:59

cette réponse est compatible avec toutes les versions depuis Python-2.5 lorsque le mot-clé with a été publié.

1. Créer un fichier s'il n'existe pas + définir l'heure actuelle

(identique à la commande 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

une version plus robuste:

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. Il suffit de créer le file if n'existe pas

(ne met pas à jour l'heure)

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

3. Il suffit de mettre à jour l'accès au fichier/Temps modifiés

(ne crée pas de fichier s'il n'existe pas)

import os

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

utilisant os.path.exists() ne simplifie pas le 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: temps de mise à Jour de tous les fichiers dans un répertoire

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)
3
répondu olibre 2018-01-11 12:41:41
with open(file_name,'a') as f: 
    pass
2
répondu Matt 2015-11-07 16:28:21

Complexe (éventuellement 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)

cela essaie de permettre aussi de définir le temps d'accès ou de modification, comme GNU touch.

1
répondu itsadok 2009-07-21 14:10:20

il peut sembler logique de créer une chaîne avec les variables désirées, et de la passer à os.système:

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

ceci est inadéquat à plusieurs égards (par exemple,il ne gère pas whitespace), alors ne le faites pas.

une méthode plus robuste est d'utiliser le sous-processus:

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

alors que c'est beaucoup mieux que d'utiliser un sous-puits (avec os.système), il est toujours seulement adapté pour rapide-et-sale scripts; utiliser la réponse acceptée pour les programmes multiplateformes.

1
répondu belacqua 2013-10-11 19:39:43

"open(nom_fichier, 'a').close () " ne fonctionnait pas pour moi en Python 2.7 sur Windows. "OS.utime(nom_fichier, Aucun)" a très bien fonctionné.

aussi, j'ai eu besoin de toucher récursivement tous les fichiers dans un répertoire avec une date plus ancienne qu'une certaine date. J'ai créé le suivi hte basé sur la réponse très utile d'ephemient.

def touch(file_name):
    # Update the modified timestamp of a file to now.
    if not os.path.exists(file_name):
        return
    try:
        os.utime(file_name, None)
    except Exception:
        open(file_name, 'a').close()

def midas_touch(root_path, older_than=dt.now(), pattern='**', recursive=False):
    '''
    midas_touch updates the modified timestamp of a file or files in a 
                directory (folder)

    Arguements:
        root_path (str): file name or folder name of file-like object to touch
        older_than (datetime): only touch files with datetime older than this 
                   datetime
        pattern (str): filter files with this pattern (ignored if root_path is
                a single file)
        recursive (boolean): search sub-diretories (ignored if root_path is a 
                  single file)
    '''
    # if root_path NOT exist, exit
    if not os.path.exists(root_path):
        return
    # if root_path DOES exist, continue.
    else:
        # if root_path is a directory, touch all files in root_path
        if os.path.isdir(root_path):
            # get a directory list (list of files in directory)
            dir_list=find_files(root_path, pattern='**', recursive=False)
            # loop through list of files
            for f in dir_list:
                # if the file modified date is older thatn older_than, touch the file
                if dt.fromtimestamp(os.path.getmtime(f)) < older_than:
                    touch(f)
                    print "Touched ", f
        # if root_path is a file, touch the file
        else:
            # if the file modified date is older thatn older_than, touch the file
            if dt.fromtimestamp(os.path.getmtime(f)) < older_than:
                touch(root_path)
1
répondu cadvena 2016-06-22 21:19:35