442

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

您将如何将其实现为 Python 函数?尝试跨平台和完整。

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

4

15 回答 15

451

看起来这是从 Python 3.4 开始的新功能 - pathlib

from pathlib import Path

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

file.txt这将在路径上创建一个。

--

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

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

于 2016-01-05T03:45:06.120 回答
251

这试图比其他解决方案更加无种族。(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 将向诸如 之类的函数添加 指定文件描述符(when ) ,这将在后台使用系统调用而不是系统调用。换句话说:os.supports_fdos.utimefutimesutimes

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)
于 2009-07-21T16:17:59.703 回答
45
def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()
于 2009-07-21T09:11:18.593 回答
35

为什么不试试这个?:

import os

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

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

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

于 2011-06-03T03:31:28.337 回答
14

当关键字发布时,此答案与 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)
于 2017-06-20T17:56:17.533 回答
10

对于更底层的解决方案,可以使用

os.close(os.open("file.txt", os.O_CREAT))
于 2020-08-26T19:48:21.670 回答
8

下面是一些使用 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())
于 2012-01-14T07:44:18.393 回答
6

简单化:

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • open确保那里有一个文件
  • 确保utime更新时间戳

理论上,可能有人会在 之后删除文件open,导致 utime 引发异常。但可以说没关系,因为确实发生了一些不好的事情。

于 2009-07-21T10:30:54.250 回答
4
with open(file_name,'a') as f: 
    pass
于 2015-11-07T00:20:57.703 回答
4

以下内容就足够了:

import os
def func(filename):
    if os.path.exists(filename):
        os.utime(filename)
    else:
        with open(filename,'a') as f:
            pass

如果要为触摸设置特定时间,请使用 os.utime,如下所示:

os.utime(filename,(atime,mtime))

在这里,atime 和 mtime 都应该是 int/float 并且应该等于纪元时间(以秒为单位)到您要设置的时间。

于 2019-12-11T11:59:14.880 回答
2

复杂(可能有问题):

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。

于 2009-07-21T10:49:18.613 回答
1

使用所需变量创建一个字符串并将其传递给 os.system 似乎是合乎逻辑的:

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

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

更健壮的方法是使用 subprocess :

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

虽然这比使用子shell(带有 os.system)要好得多,但它仍然只适用于快速和肮脏的脚本;对跨平台程序使用公认的答案。

于 2012-06-28T16:49:38.970 回答
0

你为什么不试试:newfile.py

#!/usr/bin/env python
import sys
inputfile = sys.argv[1]

with open(inputfile, 'w') as file:
    pass

python newfile.py foobar.txt

或者

使用子流程:

import subprocess
subprocess.call(["touch", "barfoo.txt"])
于 2019-09-04T17:12:34.553 回答
0

write_text()pathlib.Path可以使用。

>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0
于 2020-04-20T18:03:31.587 回答
-1

还有一个用于触摸的python模块

>>> from touch import touch
>>> touch(file_name)

你可以安装它pip install touch

于 2021-10-12T13:56:47.757 回答