如何从Python更改符号链接的atime和mtime?

如何从Python更改符号链接的atime和mtime?,python,python-2.7,filesystems,symlink,Python,Python 2.7,Filesystems,Symlink,我有一个Python2.7程序,它必须创建一个带有过去修改日期的符号链接。我可以使用os.symlink()创建链接,os.utime()声明设置文件的访问时间和修改时间,但是当我在新创建的符号链接上使用os.utime()时,它会更改符号链接指向的文件的atime和mtime,而不是符号链接的atime和mtime 从Python代码中设置符号链接的访问时间和修改时间的最佳方法是什么 下面是一个测试程序,它演示了我正在做的事情: #/usr/bin/env python2.7 导入操作系统、日

我有一个Python2.7程序,它必须创建一个带有过去修改日期的符号链接。我可以使用
os.symlink()
创建链接,
os.utime()
声明设置文件的访问时间和修改时间,但是当我在新创建的符号链接上使用
os.utime()
时,它会更改符号链接指向的文件的atime和mtime,而不是符号链接的atime和mtime

从Python代码中设置符号链接的访问时间和修改时间的最佳方法是什么

下面是一个测试程序,它演示了我正在做的事情:

#/usr/bin/env python2.7
导入操作系统、日期时间、时间
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
路径1,路径2='源','链接'
如果os.path.存在(路径1):
os.rmdir(路径1)
os.mkdir(路径1)
如果os.path.lexists(路径2):
删除操作系统(路径2)
os.symlink(路径1,“链接”)
lstat1,lstat2=os.lstat(路径1),os.lstat(路径2)
打印(“之前:{path1}atime{sa},mtime{sm},{path2}atime{la},mtime{lm}”。格式(
path1=path1,path2=path2,sa=lstat1.st_时间,sm=lstat1.st_时间,
la=lstat2.st_atime,lm=lstat2.st_mtime)
long_ago=datetime.datetime(datetime.date.today().year-1,1,00,00)
long\u ago\u posix=time.mktime(long\u ago.timetuple())
打印(“所需:{path1}未更改,{path2}atime{m},mtime{m}”。格式(
路径1=路径1,路径2=路径2,m=很久以前
utime(路径2,(long_ago_posix,long_ago_posix))
lstat1,lstat2=os.lstat(路径1),os.lstat(路径2)
打印(“之后:{path1}atime{sa},mtime{sm},{path2}atime{la},mtime{lm}”。格式(
path1=path1,path2=path2,sa=lstat1.st_时间,sm=lstat1.st_时间,
la=lstat2.st_atime,lm=lstat2.st_mtime)
这就是我看到的错误行为。“后:”时间更改为“源”,而不是“链接”,但应发生相反的情况:

%../src/utime\u symlink\u test.py
之前:源atime 1514931280.0、mtime 1514931280.0、链接atime 1514931280.0、mtime 1514931280.0
所需:源未更改,链接atime 1483257600.0,mtime 1483257600.0
之后:源atime 1483257600.0、mtime 1483257600.0、链接atime 1514931280.0、mtime 1514931280.0
%ls-ldT源链路
lrwxr-xr-x 1 myuser staff 6 2 Jan 14:14:40 2018链接->来源
drwxr-xr-x 2 myuser staff 68 2017年1月1日00:00:00来源
相比之下,
touch-h
根据需要更改符号链接的atime和mtime

%touch-h-t 201701010000链接
%ls-ldT源链路
lrwxr-xr-x 1 myuser staff 6 2017年1月1日00:00:00链接->来源
drwxr-xr-x 2 myuser staff 68 2017年1月1日00:00:00来源

也许从Python执行
touch-h
是我最好的选择,但我希望有更好的选择。

升级到Python 3.6并使用
follow\u symlinks
选项

os.utime(path2, (long_ago_posix, long_ago_posix), follow_symlinks = False)
正如所指出的,有一个参数,
follow_symlinks=False
,它给出了提问者想要的行为。不幸的是,不允许使用此参数

Python2的另一种方法是调用命令,使用。这实际上也适用于Python3。然而,我只在Mac上测试了它。它可能在Linux上工作,Linux预装了一个类似的
touch
实用程序和一个类似的进程调用约定。它没有在Windows上测试,除非您特意安装
touch
实用程序,否则可能无法在Windows上运行

这是问题的测试程序,重新编写以显示这三个选项。使用单个参数调用它,可以是
2.utime
(失败)、
3.utime
(成功,仅限Python 3)或
2.touch
(成功,可能仅限Mac或Linux)。默认值为
2.utime

import os, datetime, time, sys, subprocess

if __name__ == '__main__':
    method = 'missing' if len(sys.argv) < 2 else sys.argv[1]
    path1, path2 = 'source', 'link'
    if os.path.exists(path1):
        os.rmdir(path1)
    os.mkdir(path1)
    if os.path.lexists(path2):
        os.remove(path2)
    os.symlink(path1, 'link')

    lstat1, lstat2 = os.lstat(path1), os.lstat(path2)
    print("Before: {path1} atime {sa}, mtime {sm}, {path2} atime {la}, mtime {lm}".format(
        path1=path1, path2=path2, sa=lstat1.st_atime, sm=lstat1.st_mtime, 
        la=lstat2.st_atime, lm=lstat2.st_mtime))

    long_ago = datetime.datetime(datetime.date.today().year - 1,1,1,00,00,00)
    long_ago_posix = time.mktime(long_ago.timetuple())
    print("Desired: {path1} unchanged, {path2} atime {m}, mtime {m}".format(
        path1=path1, path2=path2, m=long_ago_posix))

    if method in ['missing', '2.utime']: 
        # runs on Python 2 or 3, always follows symbolic links
        os.utime(path2, (long_ago_posix, long_ago_posix))
    elif method in ['2.touch']:
        # runs on Python 2 or 3, tested on Mac only, maybe works on Linux, probably not Windows
        invocation = ['touch', '-h', '-t', long_ago.strftime('%Y%m%d%H%M.%S'), path2]
        subprocess.call(invocation)
    elif method in ['3.utime']:
        # runs on Python 3 only, changes links instead of following them
        os.utime(path2, (long_ago_posix, long_ago_posix), follow_symlinks=False)
    else:
        print("Don't recognise option {0}. Try 2.utime, 2.touch, or 3.utime .".format(method))

    lstat1, lstat2 = os.lstat(path1), os.lstat(path2)
    print("After: {path1} atime {sa}, mtime {sm}, {path2} atime {la}, mtime {lm}".format(
        path1=path1, path2=path2, sa=lstat1.st_atime, sm=lstat1.st_mtime, 
        la=lstat2.st_atime, lm=lstat2.st_mtime))
以下是Python 2上成功的
touch
调用(仅在Mac上测试):

%python../src/utime\u symlink\u test.py 2.touch
之前:源atime 1514961838.0、mtime 1514961838.0、链接atime 1514961838.0、mtime 1514961838.0
所需:源未更改,链接atime 1483257600.0,mtime 1483257600.0
之后:源atime 1514961838.0、mtime 1514961838.0、链接atime 1483257600.0、mtime 1483257600.0
%ls-ldT源链路
lrwxr-xr-x 1 myuser staff 6 2017年1月1日00:00:00链接->来源
drwxr-xr-x 2 myuser staff 68 2 Jan 22:43:58 2018来源

你好,吉姆·亨特。谢谢!但是,我看到一个
follow_symlinks
arg用于,但不用于。也许这意味着我该把这个程序移到Python 3上了。是的,看起来他们没有在旧版本中改进这个功能。你知道,如果你把它编辑成“使用Python 3”,并修改示例代码来演示它与Python 3一起工作,这将是一个响应性的答案。我已经添加了升级建议