touch是一个Unix实用程序,它将文件的修改和访问时间设置为一天中的当前时间。如果该文件不存在,则使用默认权限创建该文件。
如何将其实现为Python函数?尽量跨平台和完整。
(目前谷歌的“python触摸文件”的结果不是很好,但指向os.utime。)
touch是一个Unix实用程序,它将文件的修改和访问时间设置为一天中的当前时间。如果该文件不存在,则使用默认权限创建该文件。
如何将其实现为Python函数?尽量跨平台和完整。
(目前谷歌的“python触摸文件”的结果不是很好,但指向os.utime。)
当前回答
你为什么不试试: newfile.py
#!/usr/bin/env python
import sys
inputfile = sys.argv[1]
with open(inputfile, 'r+') as file:
pass
Python newfile.py foobar.txt
or
使用子流程:
import subprocess
subprocess.call(["touch", "barfoo.txt"])
其他回答
下面是一些使用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())
这个方法试图比其他解决方案更无种族限制。(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似乎没有提供一种不通过ctypes或类似的方法来调用futimes…
EDIT
正如Nate Parsons所指出的,Python 3.3将为os.supports_fd等函数添加指定文件描述符(当os.supports_fd时)。Utime,它将使用futimes系统调用,而不是在底层使用utimes系统调用。换句话说:
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)
为什么不试试呢?:
import os
def touch(fname):
try:
os.utime(fname, None)
except OSError:
open(fname, 'a').close()
我相信这消除了任何重要的竞争条件。如果文件不存在,则会抛出异常。
这里唯一可能的竞态条件是,文件是在调用open()之前,但在os.utime()之后创建的。但这并不重要,因为在这种情况下,修改时间将如预期的那样,因为它必须发生在调用touch()期间。
我有一个用于备份的程序:https://stromberg.dnsalias.org/~strombrg/backshift/
我使用vmprof对它进行了分析,发现到目前为止,触摸是最耗时的部分。
所以我研究了快速接触文件的方法。
我发现在CPython 3.11上,这是最快的:
def touch3(filename, flags=os.O_CREAT | os.O_RDWR):
"""Touch a file using os.open+os.close - fastest on CPython 3.11."""
os.close(os.open(filename, flags, 0o644))
在Pypy3 7.3.9上,这是最快的:
def touch1(filename):
"""Touch a file using pathlib - fastest on pypy3, and fastest overall."""
Path(filename).touch()
在这两者中,pypy3的最佳性能仅略快于cpython的最佳性能。
我可能有一天会创建一个关于这个的网页,但现在我所拥有的只是一个Subversion repo: https://stromberg.dnsalias.org/svn/touch/trunk 它包括我尝试过的4种触摸方式。
Write_text()从pathlib。路径可以使用。
>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0