在Mac上使用Python获取文件创建时间

12

在Mac(以及通用的Unix系统)上,Python的os.path.getctime函数无法提供文件创建时间,而只能提供“最后更改时间”(至少按照文档所述)。但是,在Finder中,我可以看到实际的文件创建时间,因此HFS+将此信息保存。

你有什么建议可以在Python程序中获取Mac上的文件创建时间吗?


重复:https://dev59.com/G3VC5IYBdhLWcg3wnCj6 - S.Lott
1
@S.Lott:并不是真的,因为在Mac上获取文件创建时间本质上是非跨平台的。 - Miles
@Miles:也许是真的,但那里的答案完美地适用于这个问题。 - S.Lott
1
@S.Lott:这不是重复的问题,相信我,那里的答案根本不适用于Mac(除非你认为答案是在Mac上无法获取创建时间,而Miles已经证明这是错误的)。在Mac上,os.path.getctime和os.stat都提供了最后一次更改时间,而不是创建时间。因此,所有声称os.stat是跨平台获取创建时间的方法的人都是错误的。 - cefstat
3个回答

25

在调用 os.stat() (或者 fstat/lstat)之后,可以使用结果的 st_birthtime 属性。

def get_creation_time(path):
    return os.stat(path).st_birthtime

您可以使用datetime.datetime.fromtimestamp()将整数结果转换为日期时间对象。

由于某些原因,当这个答案第一次写的时候,在Mac OS X上似乎不起作用,但我可能错了,现在它可以工作,即使是在旧版本的Python上也可以。下面是旧答案,供参考。


使用ctypes访问系统调用stat64(适用于Python 2.5+):

from ctypes import *

class struct_timespec(Structure):
    _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]

class struct_stat64(Structure):
    _fields_ = [
        ('st_dev', c_int32),
        ('st_mode', c_uint16),
        ('st_nlink', c_uint16),
        ('st_ino', c_uint64),
        ('st_uid', c_uint32),
        ('st_gid', c_uint32), 
        ('st_rdev', c_int32),
        ('st_atimespec', struct_timespec),
        ('st_mtimespec', struct_timespec),
        ('st_ctimespec', struct_timespec),
        ('st_birthtimespec', struct_timespec),
        ('dont_care', c_uint64 * 8)
    ]

libc = CDLL('libc.dylib') # or /usr/lib/libc.dylib
stat64 = libc.stat64
stat64.argtypes = [c_char_p, POINTER(struct_stat64)]

def get_creation_time(path):
    buf = struct_stat64()
    rv = stat64(path, pointer(buf))
    if rv != 0:
        raise OSError("Couldn't stat file %r" % path)
    return buf.st_birthtimespec.tv_sec

使用subprocess调用stat实用程序:

import subprocess

def get_creation_time(path):
    p = subprocess.Popen(['stat', '-f%B', path],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if p.wait():
        raise OSError(p.stderr.read().rstrip())
    else:
        return int(p.stdout.read())

2
在El Capitan上,如果你遇到OSError: dlopen(libc.dylib, 6): image not found错误,你可能需要使用libc = CDLL('/usr/lib/libc.dylib')而不是libc = CDLL('libc.dylib') - Thomas Orozco
@ThomasOrozco 原来有比 ctypes 更好的方法。 - Miles

3

平台上的ctime不同:在一些系统(如Unix)中,它是最后元数据更改的时间,在另一些系统(如Windows)中,它是创建时间。这是因为Unix通常不保留“原始”创建时间。

尽管如此,您仍然可以通过stat模块访问操作系统提供的所有信息。

stat模块定义了常量和函数,用于解释os.stat()、os.fstat()和os.lstat() (如果存在)的结果。有关stat、fstat和lstat调用的完整详细信息,请参阅您系统的文档。

stat.ST_CTIME
由操作系统报告的“ctime”。在一些系统(如Unix)中,它是最后元数据更改的时间,在另一些系统(如Windows)中,它是创建时间(有关详细信息,请参阅平台文档)。


谢谢,但是... stat.ST_CTIME:由操作系统报告的“ctime”。在某些系统(如Unix)上,它是最后一次元数据更改的时间,在其他系统(如Windows)上,则是创建时间(有关详细信息,请参阅平台文档)。 - cefstat
1
@cefstat 这就是问题所在。有些系统(比如Unix)根本就没有提供“原始”创建时间。Python对此无能为力。 - lothar

3
由于缺乏好用的工具,我创建了crtime
pip install crtime

然后你可以像这样使用它:
sudo crtime ./

将打印:

1552938281  /home/pascal/crtime/.gitignore
1552938281  /home/pascal/crtime/README.md
1552938281  /home/pascal/crtime/crtime
1552938281  /home/pascal/crtime/deploy.py
1552938281  /home/pascal/crtime/setup.cfg
1552938281  /home/pascal/crtime/setup.py
1552938961  /home/pascal/crtime/crtime.egg-info
1552939447  /home/pascal/crtime/.git
1552939540  /home/pascal/crtime/build
1552939540  /home/pascal/crtime/dist

请注意,对于大型目录,它比有时被提到的xstat要快1000倍以上,因为它会创建临时文件,然后一次性执行所有文件的stat调用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接