使用Python实现触摸?

touch是一个Unix实用程序,它将文件的修改和访问时间设置为当前时间。 如果该文件不存在,则使用默认权限创build该文件。

你将如何实现它作为一个Python函数? 尝试跨平台和完整。

(目前谷歌的“python touch file”结果不是很好,但指向os.utime 。)

这试图比其他的解决scheme更无赛跑。 ( 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或类似的…


编辑

正如Nate Parsons所指出的那样,Python 3.3将在os.supports_fd函数中添加 一个文件描述符 (当os.supports_fd ),该函数将使用futimes系统调用而不是引擎盖下的系统调用。 换一种说法:

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

这将在path中创build一个file.txt

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

在这个给定的path创build一个文件。 如果给出模式,则将其与进程的umask值组合以确定文件模式和访问标志。 如果文件已经存在,则函数成功,如果exist_ok为真(并且其修改时间更新为当前时间),否则引发FileExistsError。

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

为什么不试试这个?

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

我相信这消除了任何重要的竞争条件。 如果文件不存在,则会抛出exception。

这里唯一可能的竞争条件是如果文件是在open()被调用之前创build的,但是在os.utime()之后。 但这并不重要,因为在这种情况下,修改时间将与预期相同,因为在调用touch()期间必定发生。

以下是一些使用ctypes的代码(仅在Linux上testing过):

 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引发exception。 但可以说没关系,因为发生了一些不好的事情。

这个答案与自Python-2.5以来的所有版本兼容,当关键字with释放。

1.设置当前时间,创build文件如果不存在 (与命令touch完全相同)

 import os with open(fname, 'a'): # Create file if does not exist os.utime(fname, None) # Set access/modified times to now 

更健壮的版本:

 import os with open(fname, 'a'): try: os.utime(fname, None) except OSError: print('File has just been deleted between open() and os.utime() calls') 

2.只要创build文件,如果不存在 (不更新时间)

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

3.只更新文件访问权限/修改时间 (如果不存在则不创build文件)

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

使用os.path.exists()不会简化代码:

 import os if os.path.exists(fname): try: os.utime(fname, None) # Set access/modified times to now except OSError: print('File has just been deleted between exists() and utime() calls (or no permission)') 

奖励:更新目录中所有文件的时间

 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 file=%s because %s', pathname, why) print('Changed time of %s files', number_of_files) 
 with open(file_name,'a') as f: pass 

复杂(可能是越野车):

 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。

使用所需的variables创build一个string似乎是合乎逻辑的,并将其传递给os.system:

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

这在许多方面是不够的(例如,它不处理空白),所以不要这样做。

更健壮的方法是使用subprocess:

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

虽然这比使用子shell(使用os.system)要好得多,但它仍然只适用于快捷脚本; 使用跨平台程序的接受答案。

“open(file_name,'a')。close()”在Windows上的Python 2.7中不起作用。 “os.utime(file_name,None)”工作得很好。

此外,我需要recursion地触摸date比某个date更早的目录中的所有文件。 我根据ephemient的非常有帮助的反应创build了以下。

 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)