Реализовать touch с помощью Python?
touch
- это утилита Unix, которая устанавливает время изменения и доступа к файлам в текущее время суток. Если файл не существует, он создается с разрешениями по умолчанию.
Как бы вы реализовали его как функцию Python? Постарайтесь быть кросс-платформенным и полным.
(текущие результаты Google для "Python touch file" не так велики, но указывают на os.utime.)
11 ответов
это пытается быть немного более свободным от гонки, чем другие решения. (The with
ключевое слово является новым в Python 2.5.)
import os
def touch(fname, times=None):
with open(fname, 'a'):
os.utime(fname, times)
примерно эквивалентно этому.
import os
def touch(fname, times=None):
fhandle = open(fname, 'a')
try:
os.utime(fname, times)
finally:
fhandle.close()
теперь, чтобы действительно сделать его свободным от гонки, вам нужно использовать futimes
и измените метку времени открытого файла, вместо того, чтобы открывать файл, а затем изменять метку времени в имени файла (который, возможно, был переименован). К сожалению, Python, похоже, не предоставляет способ звоните futimes
, минуя ctypes
или аналогичные...
редактировать
как отмечает Нейт Парсонс, в Python 3.3 будет добавить указать файл дескриптора (при os.supports_fd
) для таких функций, как os.utime
, который будет использовать futimes
syscall вместо utimes
syscall под капотом. Другими словами:
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)
похоже, что это новое с Python 3.4 -pathlib
.
from pathlib import Path
Path('path/to/file.txt').touch()
Это создаст file.txt
на пути.
--
путь.touch (mode=0o777, exist_ok=True)
создайте файл по этому пути. Если задан режим, он объединяется со значением umask процесса для определения режима файла и флагов доступа. Если файл уже существует, функция выполняется успешно, если exist_ok имеет значение true (и время его изменения обновлено до текущего времени), в противном случае возникает FileExistsError.
почему бы не попробовать это?:
import os
def touch(fname):
try:
os.utime(fname, None)
except OSError:
open(fname, 'a').close()
Я считаю, что это устраняет любые условия гонки, которые имеют значение. Если файл не существует, будет создано исключение.
единственное возможное условие гонки здесь - Если файл создан до вызова open (), но после os.utime (). Но это не имеет значения, потому что в этом случае время модификации будет таким, как ожидалось, поскольку это должно было произойти во время вызова touch().
вот код, который использует ctypes (тестируется только в 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())
упрощенно:
def touch(fname):
open(fname, 'a').close()
os.utime(fname, None)
- на
open
обеспечивает есть файл - на
utime
гарантирует, что временные метки будут обновлены
теоретически, возможно, кто-то удалит файл после open
, в результате чего utime вызывает исключение. Но, возможно, это нормально, так как случилось что-то плохое.
этот ответ совместим со всеми версиями, начиная с Python-2.5, когда ключевое слово with
была отпущена.
1. Создать файл, если не существует + установить текущее время
(точно так же, как команда 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
более надежная версия:
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. Просто создайте файл, если не существует
(не обновляет время)
with open(fname, 'a'): # Create file if does not exist
pass
3. Просто обновить доступ к файлам / измененное время
(не создает файл, если он не существует)
import os
try:
os.utime(fname, None) # Set access/modified times to now
except OSError:
pass # File does not exist (or no permission)
используя os.path.exists()
не упрощай код:
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)
бонус: обновления всех файлов в директории
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)
комплекс (возможно с ошибками):
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)
это также позволяет установить время доступа или модификации, например GNU touch.
может показаться логичным создать строку с нужными переменными и передать ее в ОС.система:
touch = 'touch ' + dir + '/' + fileName
os.system(touch)
это неадекватно по ряду причин (например,он не обрабатывает пробелы), поэтому не делайте этого.
более надежным методом является использование подпроцесса:
subprocess.call(['touch', os.path.join(dirname, fileName)])
хотя это намного лучше, чем использование подрешетки (с ОС.система), по-прежнему подходит только для быстрых и грязных скриптов; используйте принятый ответ для кросс-платформенных программы.
"открыть (имя_файла, 'a').close ()" не работал для меня в Python 2.7 на Windows. "ОС.utime (имя_файла, нет)" работал просто отлично.
кроме того, мне нужно было рекурсивно коснуться всех файлов в каталоге с датой старше некоторой даты. Я создал hte, основываясь на очень полезном ответе 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)