web-dev-qa-db-fra.com

Implémenter le toucher en utilisant Python?

touch est un utilitaire Unix qui définit les heures de modification et d'accès des fichiers à l'heure actuelle. Si le fichier n'existe pas, il est créé avec les autorisations par défaut.

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

(Les résultats Google actuels pour "python touch file" ne sont pas très bons, mais pointez vers os.utime .)

278
itsadok

On dirait que cela est nouveau à partir de Python 3.4 - pathlib .

from pathlib import Path

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

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

-

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

Créez un fichier à ce chemin donné. Si mode est spécifié, il est combiné à la valeur umask du processus pour déterminer le mode de fichier et les indicateurs d’accès. Si le fichier existe déjà, la fonction réussit si exist_ok est true (et son heure de modification est mise à jour à l'heure actuelle), sinon FileExistsError est levé.

202
voidnologo

Cela tente d'être un peu plus libre de la course que les autres solutions. (Le mot clé with est nouveau dans Python 2.5.)

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

À peu près équivalent à cela.

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

Maintenant, pour vraiment éviter la course, vous devez utiliser futimes et modifier l’horodatage du descripteur de fichier ouvert, au lieu d’ouvrir le fichier, puis de modifier l’horodatage du nom de fichier (éventuellement renommé). ) Malheureusement, Python ne semble pas fournir un moyen d'appeler futimes sans passer par ctypes ou similaire ...


EDIT

Comme indiqué par Nate Parsons , Python 3.3 va ajouterspécifier un descripteur de fichier (when os.supports_fd ) vers des fonctions telles que os.utime , qui utilisera le futimes syscall au lieu du utimes syscall sous le capot. 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)
_
232
ephemient
def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()
39
SilentGhost

Pourquoi ne pas essayer ça ?:

import os

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

Je crois que cela élimine toute condition de concurrence critique qui compte. Si le fichier n'existe pas, une exception sera levée.

La seule condition de concurrence possible ici est si le fichier est créé avant que open () soit appelé, mais après os.utime (). Mais cela n’a pas d’importance, car dans ce cas, le temps de modification sera celui attendu, car il doit s’être passé pendant l’appel de touch ().

26
jcoffland

Voici un code qui utilise ctypes (testé uniquement sous 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
eug

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 + Régler 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. Créez simplement le fichier s'il 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 les accès au fichier/les 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)

Utiliser 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: Heure de mise à jour de tous les fichiers d'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)
7
olibre
with open(file_name,'a') as f: 
    pass
3
Matt

Simpliste:

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • Le open assure qu'il y a un fichier
  • le utime s'assure que les horodatages sont mis à jour

Théoriquement, il est possible que quelqu'un supprime le fichier après le open, ce qui entraînera une exception. Mais on peut dire que ça va, car quelque chose de grave est arrivé.

3
itsadok

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

De plus, j'avais besoin de toucher de manière récursive tous les fichiers d'un répertoire dont la date était antérieure à une date donnée. J'ai créé le suivi suivant basé sur la réponse très utile de l'éphémère.

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
cadvena

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)

Ceci essaie également de permettre le réglage de l'heure d'accès ou de modification, comme GNU touch.

1
itsadok

Il peut sembler logique de créer une chaîne avec les variables souhaitées et de la transmettre à os.system:

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

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

Une méthode plus robuste consiste à utiliser un sous-processus:

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

Bien que cela soit bien mieux que d’utiliser un sous-shell (avec os.system), cela ne convient toujours que pour les scripts rapides et sales; utilisez la réponse acceptée pour les programmes multiplates-formes.

1
Manoj