529 votes

Implémenter le tactile en utilisant Python ?

touch est un utilitaire Unix qui définit les heures de modification et d'accès aux fichiers en fonction de l'heure du jour. Si le fichier n'existe pas, il est créé avec les permissions par défaut.

Comment l'implémenter en tant que fonction Python ? Essayez d'être multiplateforme et complet.

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

7 votes

Veuillez envisager de mettre à jour la réponse acceptée maintenant que cette fonctionnalité est intégrée dans la stdlib de Python.

0 votes

@Miles La réponse acceptée fait exactement ce que la question demandait - elle implémente la fonction en Python au lieu d'utiliser une bibliothèque.

10 votes

@styrofoamfly La bibliothèque standard est de Python. Il est très probable que ce que l'auteur de la question veut vraiment savoir (et la plupart des gens qui arrivent à cette question via Google) est comment obtenir touch -dans leurs programmes Python, et non comment les réimplémenter à partir de zéro ; ces personnes sont mieux servies en défilant vers le bas jusqu'à la page d'accueil. pathlib solution. Même si elle est maintenant intégrée, cette réponse a un bien meilleur classement dans Google pour "python touch file" que la documentation pertinente .

256voto

ephemient Points 87003

Cette solution tente d'être un peu plus exempte de race que les autres. (Les with est nouveau dans Python 2.5).

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

C'est à peu près l'équivalent de ce qui suit.

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

Maintenant, pour qu'il n'y ait vraiment pas de course, vous devez utiliser futimes et modifier l'horodatage du dossier ouvert, au lieu d'ouvrir le fichier et de modifier ensuite l'horodatage du nom de fichier (qui peut avoir été renommé). Malheureusement, Python ne semble pas fournir de moyen d'appeler futimes sans passer par ctypes ou similaire...


EDITAR

Comme l'a noté Nate Parsons Python 3.3 sera ajouter spécifier un descripteur de fichier (lorsque os.supports_fd ) à des fonctions telles que os.utime qui utilisera l'option futimes au lieu de l'appel système 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)

0 votes

C'est la vraie solution - et c'est ainsi que touch(1) dans coreutils le fait, à moins que futimes() ne soit pas disponible. futimes n'est pas une fonction portable et n'existe même pas sur les anciens noyaux Linux 2.6, vous devez donc vous occuper d'ENOSYS et revenir à utime même si vous l'utilisez.

0 votes

(Erreur de relecture ci-dessus : "This" = open("a") + futimes.) Heureusement, il est difficile de penser à un cas où la condition de course de ne pas utiliser futimes est réellement importante. Le "mauvais" cas auquel vous pourriez être confronté est celui d'un fichier renommé entre open() et utime(), auquel cas vous ne créerez pas de nouveau fichier et ne toucherez pas à l'ancien. Cela peut avoir de l'importance, mais la plupart du temps ce n'est pas le cas.

0 votes

Cygwin touch peut faire sa magie sur les fichiers en lecture seule, mais ce code ne le peut pas. However it seems to work if I surround it with try: <code> except IOError as e : (check e.errno) os.utime(filename, times)

51voto

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

10 votes

Il s'agit d'un accord. La bonne solution est juste : def touch(fname) : open(fname, 'wa').close()

0 votes

@Greg, tout en résolvant le problème des conditions de course potentielles, open(fname, 'a').close() ne changera pas au fil du temps.

0 votes

@SilentGhost : C'est vrai, mais ce n'est pas grave car si le fichier existe, c'est qu'il a été créé. juste créé. Bien entendu, vous laisserez l'appel à os.utime() pour les fichiers préexistants.

37voto

jcoffland Points 1506

Pourquoi ne pas essayer ceci ?

import os

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

Je pense que cela élimine toute condition de course importante. Si le fichier n'existe pas, une exception sera levée.

La seule condition de concurrence possible ici est que le fichier soit créé avant l'appel à open() mais après os.utime(). Mais cela n'a pas d'importance car, dans ce cas, le temps de modification sera conforme aux attentes puisqu'il a dû se produire pendant l'appel à touch().

8voto

eug Points 153

Voici du 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())

6voto

itsadok Points 12971

Simplicité :

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • En open s'assure qu'il y a un fichier à cet endroit
  • les utime garantit la mise à jour des horodatages

Théoriquement, il est possible que quelqu'un supprime le fichier après que le open ce qui conduit utime à lever une exception. Mais on peut dire que ce n'est pas grave, puisqu'il s'est passé quelque chose de grave.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X