使用Python实现触摸?

发布于 2024-07-28 04:00:16 字数 272 浏览 11 评论 0原文

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

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

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

touch is a Unix utility that sets the modification and access times of files to the current time of day. If the file doesn't exist, it is created with default permissions.

How would you implement it as a Python function? Try to be cross platform and complete.

(Current Google results for "python touch file" are not that great, but point to os.utime.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

往昔成烟 2024-08-04 04:02:03

我有一个用于备份的程序: 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 存储库:
https://stromberg.dnsalias.org/svn/touch/trunk
它包括我尝试过的 4 种触摸方式。

I have a program that I use for backups: https://stromberg.dnsalias.org/~strombrg/backshift/

I profiled it using vmprof, and identified that touch was by far the most time-consuming part of it.

So I looked into ways of touching files quickly.

I found that on CPython 3.11, this was the fastest:

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

                                                                                

And on Pypy3 7.3.9, this was the fastest:

def touch1(filename):                                                                                                                
    """Touch a file using pathlib - fastest on pypy3, and fastest overall."""                                                        
    Path(filename).touch()                                                                                                           

Of the two, pypy3's best was only slightly faster cpython's best.

I may create a web page about this someday, but for now all I have is a Subversion repo:
https://stromberg.dnsalias.org/svn/touch/trunk
It includes the 4 ways of doing touches I tried.

甜警司 2024-08-04 04:01:55

你为什么不尝试一下:
新文件.py

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

with open(inputfile, 'r+') as file:
    pass

python newfile.py foobar.txt

使用子进程:

import subprocess
subprocess.call(["touch", "barfoo.txt"])

Why don't you try:
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

use subprocess:

import subprocess
subprocess.call(["touch", "barfoo.txt"])
几味少女 2024-08-04 04:01:47

还有一个用于 touch 的 python 模块,

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

您可以使用 pip install touch 安装它

There is also a python module for touch

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

You can install it with pip install touch

把昨日还给我 2024-08-04 04:01:40

可以使用 pathlib.Path 中的 write_text()

>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0

write_text() from pathlib.Path can be used.

>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0
云朵有点甜 2024-08-04 04:01:34

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

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

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

更可靠的方法是使用 subprocess :

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

虽然这比使用 subshel​​l (使用 os.subprocess )要好得多。 system),它仍然只适合快速而肮脏的脚本; 使用跨平台程序的公认答案。

It might seem logical to create a string with the desired variables, and pass it to os.system:

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

This is inadequate in a number of ways (e.g.,it doesn't handle whitespace), so don't do it.

A more robust method is to use subprocess :

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

While this is much better than using a subshell (with os.system), it is still only suitable for quick-and-dirty scripts; use the accepted answer for cross-platform programs.

夢归不見 2024-08-04 04:01:27

复杂(可能有错误):

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 一样。

Complex (possibly buggy):

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)

This tries to also allow setting the access or modification time, like GNU touch.

柒七 2024-08-04 04:01:21

以下内容就足够了:

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,并且应该等于您想要的时间的纪元时间(以秒为单位)放。

The following is sufficient:

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

If you want to set a specific time for touch, use os.utime as follows:

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

Here, atime and mtime both should be int/float and should be equal to epoch time in seconds to the time which you want to set.

感悟人生的甜 2024-08-04 04:01:14
with open(file_name,'a') as f: 
    pass
with open(file_name,'a') as f: 
    pass
梦在深巷 2024-08-04 04:01:07

简单化:

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

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

Simplistic:

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • The open ensures there is a file there
  • the utime ensures that the timestamps are updated

Theoretically, it's possible someone will delete the file after the open, causing utime to raise an exception. But arguably that's OK, since something bad did happen.

为你鎻心 2024-08-04 04:01:02

下面是一些使用 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())

Here's some code that uses ctypes (only tested on 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())
雪花飘飘的天空 2024-08-04 04:00:55

当关键字 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)

This answer is compatible with all versions since Python-2.5 when keyword with has been released.

1. Create file if does not exist + Set current time
(exactly same as command 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

A more robust version:

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. Just create the file if does not exist
(does not update time)

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

3. Just update file access/modified times
(does not create file if not existing)

import os

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

Using os.path.exists() does not simplify the code:

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)

Bonus: Update time of all files in a directory

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)
夏尔 2024-08-04 04:00:49

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

os.close(os.open("file.txt", os.O_CREAT))

进行比较, GNU touch 使用

O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY

模式MODE_RW_UGO,即0o666

For a more low-level solution one can use

os.close(os.open("file.txt", os.O_CREAT))

For comparison, GNU touch uses

O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY

with a mode of MODE_RW_UGO, which is 0o666.

落日海湾 2024-08-04 04:00:44

为什么不尝试这个?:

import os

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

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

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

Why not try this?:

import os

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

I believe this eliminates any race condition that matters. If the file does not exist then an exception will be thrown.

The only possible race condition here is if the file is created before open() is called but after os.utime(). But this does not matter because in this case the modification time will be as expected since it must have happened during the call to touch().

与他有关 2024-08-04 04:00:39
def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()
def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()
暮倦 2024-08-04 04:00:34

这试图比其他解决方案更加无竞争。 (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 的方法...


编辑

正如 Nate Parsons,Python 3.3 将 添加 指定文件描述符 (当 os.supports_fd 时诸如 os.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)

This tries to be a little more race-free than the other solutions. (The with keyword is new in Python 2.5.)

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

Roughly equivalent to this.

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

Now, to really make it race-free, you need to use futimes and change the timestamp of the open filehandle, instead of opening the file and then changing the timestamp on the filename (which may have been renamed). Unfortunately, Python doesn't seem to provide a way to call futimes without going through ctypes or similar...


EDIT

As noted by Nate Parsons, Python 3.3 will add specifying a file descriptor (when os.supports_fd) to functions such as os.utime, which will use the futimes syscall instead of the utimes syscall under the hood. In other words:

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)
毁梦 2024-08-04 04:00:28

看起来这是 Python 3.4 的新功能 - pathlib< /代码>

from pathlib import Path

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

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

--

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

在此给定路径中创建一个文件。 如果给出了模式,它将与进程的 umask 值结合起来确定文件模式和访问标志。 如果文件已存在,则当 exit_ok 为 true 时该函数成功(并且其修改时间更新为当前时间),否则引发 FileExistsError 。

Looks like this is new as of Python 3.4 - pathlib.

from pathlib import Path

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

This will create a file.txt at the path.

--

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

Create a file at this given path. If mode is given, it is combined with the process’ umask value to determine the file mode and access flags. If the file already exists, the function succeeds if exist_ok is true (and its modification time is updated to the current time), otherwise FileExistsError is raised.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文