ChatGPT解决这个技术问题 Extra ChatGPT

如何获取文件创建和修改日期/时间?

获取文件创建和修改日期/时间的最佳跨平台方法是什么,适用于 Linux 和 Windows?

您无法以跨平台的方式获取文件创建时间。请参阅docs.python.org/library/os.path.html#os.path.getctime
请注意,不再推荐接受的答案,请使用 pathlib 而不是 os,请参阅@StevenC.Howell 的答案。也许甚至可以将接受的答案更改为 pathlib 答案?
@questionto42,虽然我同意,但给出建议的理由可能是值得的。仅通过查看此 SO 帖子,许多人会看到(来自@StephenCHowell 的回答)pathlib 正在包装 os,然后问使用 pathlib 有什么意义呢?据我了解,答案是 pathlib 的命名空间比 os 小,通常会产生更简洁的代码。
@Jlanger我写了这个,因为我有复杂的递归+路径检查+文件名替换在更大文件系统上的复杂代码,直到我找到pathlib。 Pathlib 更简单、更干净——我什至记得它更强大,因为它的 Path 对象,因此更 Pythonic。更小的命名空间不是重点。如果像这样频繁使用的 Q/A 传播旧的编程方式是很危险的,我用了 os 并浪费了时间和精力,因此发表了评论。您可以通过快速 Internet 搜索找到更多 pathlibos
@questionto42 完全同意,我知道这些差异,我试图简明扼要,你比我澄清得更好。

i
igracia

以跨平台方式获取某种修改日期很容易 - 只需调用 os.path.getmtime(path),您将获得上次修改 path 处的文件时的 Unix 时间戳。

另一方面,获取文件创建日期是繁琐且依赖于平台的,甚至在三大操作系统之间也有所不同:

在 Windows 上,文件的 ctime(记录在 https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx)存储其创建日期。您可以在 Python 中通过 os.path.getctime() 或调用 os.stat() 的结果的 .st_ctime 属性来访问它。这在 Unix 上不起作用,其中 ctime 是最后一次更改文件的属性或内容。

在 Mac 以及其他一些基于 Unix 的操作系统上,您可以使用调用 os.stat() 的结果的 .st_birthtime 属性。

在 Linux 上,这目前是不可能的,至少在没有为 Python 编写 C 扩展的情况下是不可能的。尽管一些 Linux 常用的文件系统确实存储了创建日期(例如,ext4 将它们存储在 st_crtime 中),但 Linux 内核没有提供访问它们的方法;特别是,它从 C 中的 stat() 调用返回的结构,从最新的内核版本开始,不包含任何创建日期字段。您还可以看到,标识符 st_crtime 目前在 Python 源代码中的任何地方都没有。至少如果你在 ext4 上,数据会附加到文件系统中的 inode 上,但没有方便的方法来访问它。 Linux 上最好的方法是通过 os.path.getmtime() 或 os.stat() 结果的 .st_mtime 属性访问文件的 mtime。这将为您提供上次修改文件内容的时间,这对于某些用例可能已经足够了。

将所有这些放在一起,跨平台代码应该看起来像这样......

import os
import platform

def creation_date(path_to_file):
    """
    Try to get the date that a file was created, falling back to when it was
    last modified if that isn't possible.
    See http://stackoverflow.com/a/39501288/1709587 for explanation.
    """
    if platform.system() == 'Windows':
        return os.path.getctime(path_to_file)
    else:
        stat = os.stat(path_to_file)
        try:
            return stat.st_birthtime
        except AttributeError:
            # We're probably on Linux. No easy way to get creation dates here,
            # so we'll settle for when its content was last modified.
            return stat.st_mtime

我已经尽我所能把它放在一起(并在这个过程中花了几个小时研究),我相信它至少比以前的答案更正确,但这是一个非常难的话题,如果人们能提供任何更正、澄清或其他意见,我将不胜感激。特别是,我想构建一种在 Linux 下访问 ext4 驱动器上的数据的方法,并且我想了解当 Linux 读取 Windows 写入的文件时会发生什么,反之亦然,因为它们使用 {2 } 不同。
坦率地说,文件创建时间通常是无用的。当您使用模式 "w" 打开现有文件进行写入时,它不会替换它,它只是打开现有文件并截断它。即使文件内容与创建时的内容完全无关,您仍然会被告知该文件是在当前版本之前“创建”的。相反,在保存时使用原子替换(原始文件被新的正在进行的临时文件替换)的编辑器将显示更新的创建日期,即使您只是删除了一个字符。使用修改时间,不要贪图创建时间。
多年后,我终于找到了文件创建时间的用途!我正在编写代码来检查某些目录中的文件命名约定,所以首先我想考虑在制定约定后首先命名的文件。替换整个内容(mtime)是无关紧要的:如果它已经在那里,那么它就被继承了。
嗨,马克。我建议简化。在 Linux 上,返回 stat.st_ctime 更相关,因为在许多情况下,最后一次元数据更改的时间可以是创建时间(至少 ctime 更接近真正的创建时间mtime)。因此,您可以简单地将您的代码段替换为 stat = os.stat(path_to_file); try: return stat.st_birthtime; except AttributeError: return stat.st_ctime。你怎么看?干杯
@olibre “至少 ctime 比 mtime 更接近实际创建时间” - 不,不是;这是我多次看到的,但它完全是错误的。除非您手动弄乱了 inode 中的值,否则 ctime 应该始终等于或晚于 mtime,因为 mtime 更改导致 ctime 更改(因为 mtime 本身被视为“元数据”)。请参阅 stackoverflow.com/a/39521489/1709587,其中我提供了一些示例代码来说明这一点。
P
Peter Mortensen

你有几个选择。一方面,您可以使用 os.path.getmtimeos.path.getctime 函数:

import os.path, time
print("last modified: %s" % time.ctime(os.path.getmtime(file)))
print("created: %s" % time.ctime(os.path.getctime(file)))

您的另一个选择是使用 os.stat

import os, time
(mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(file)
print("last modified: %s" % time.ctime(mtime))

注意ctime()不是指的是 *nix 系统上的创建时间,而是指上次 inode 数据更改的时间。 (感谢评论中的 kojiro for making that fact more clear,提供了一个有趣的博客文章的链接。)


以防万一有人错过了@Glyph 对问题的评论,ctime does not mean creation time on POSIX systems。我想知道在过去的三年里有多少人浏览过这篇文章并继续编写错误代码。
请记住,第一个示例为您提供了一个字符串,而不是日期时间或数字。
@kojiro 您链接到的博客文章可能更明确,在 Unix 上,文件的 ctime 会在 mtime 执行时更新(因为 mtime 是“元数据”),因此 ctime 通常是总是等于或早于 mtime。因此,将 ctime 视为“已创建”时间毫无意义。 -1!
您的第一个选项为文件创建和最后修改返回相同的结果! Last modified: Fri Jan 31 11:08:13 2020Created: Fri Jan 31 11:08:13 2020 在 Linux Ubuntu 16.04 上!
我发现 time.ctime(os.path.getmtime(file)) 返回 2 种类型的字符串,具体取决于文件是否已被系统或用户修改。如果它已被系统修改,则字符串将在月和日之间有 2 个空格。我不知道为什么
P
Peter Mortensen

为此使用的最佳函数是 os.path.getmtime()。在内部,这仅使用 os.stat(filename).st_mtime

datetime 模块最适合处理时间戳,因此您可以将修改日期作为 datetime 对象获取,如下所示:

import os
import datetime
def modification_date(filename):
    t = os.path.getmtime(filename)
    return datetime.datetime.fromtimestamp(t)

使用示例:

>>> d = modification_date('/var/log/syslog')
>>> print d
2009-10-06 10:50:01
>>> print repr(d)
datetime.datetime(2009, 10, 6, 10, 50, 1)

这个答案也有点错误。 getmtime 是 Unix 上最接近可用的东西(无法获取创建日期),但绝对不是在 Windows 上使用的最佳功能,其中 ctime 是创建时间。
@MarkAmery - 这个答案被清楚地标记为只是关于修改时间。
我强烈建议在此处使用 datetime.datetime.fromtimestamp(t, tz=datetime.timezone.utc),否则返回的天真 datetime 对象倾向于被解释为位于本地时区,而 Unix 时间戳总是相对于 01.01.1970 00:00 UTC。
S
Steven C. Howell

在 Python 3.4 及更高版本中,您可以使用面向对象的 pathlib module 接口,该接口包含大部分 os 模块的包装器。这是获取文件统计信息的示例。

>>> import pathlib
>>> fname = pathlib.Path('test.py')
>>> assert fname.exists(), f'No such file: {fname}'  # check that the file exists
>>> print(fname.stat())
os.stat_result(st_mode=33206, st_ino=5066549581564298, st_dev=573948050, st_nlink=1, st_uid=0, st_gid=0, st_size=413, st_atime=1523480272, st_mtime=1539787740, st_ctime=1523480272)

有关 os.stat_result 所含内容的详细信息,请参阅 the documentation。对于您想要的修改时间 fname.stat().st_mtime

>>> import datetime
>>> mtime = datetime.datetime.fromtimestamp(fname.stat().st_mtime, tz=datetime.timezone.utc)
>>> print(mtime)
datetime.datetime(2018, 10, 17, 10, 49, 0, 249980)

如果您想要 Windows 上的创建时间,或 Unix 上最近的元数据更改,您可以使用 fname.stat().st_ctime

>>> ctime = datetime.datetime.fromtimestamp(fname.stat().st_ctime, tz=datetime.timezone.utc)
>>> print(ctime)
datetime.datetime(2018, 4, 11, 16, 57, 52, 151953)

This article 包含有关 pathlib 模块的更多有用信息和示例。


我强烈建议,正如前面的回答者所提到的,在这里使用 datetime.datetime.fromtimestamp(t, tz=datetime.timezone.utc),否则返回的天真 datetime 对象倾向于被解释为在本地时区,而 Unix 时间戳总是相对于 01.01。世界标准时间 1970 年 00:00。
P
Peter Mortensen

os.stat

在较新的代码中,您可能应该使用 os.path.getmtime() (thanks, Christian Oudard)。

但请注意,它返回 time_t 的浮点值,带有小数秒(如果您的操作系统支持它)。


os.path.getmtime() 就是为此而设计的,而且更简单。
这里的“in newer code”条款有点误导。 os.path.getmtime() 自 Python 1.5.2(请参阅 old docs)以来一直存在,在我失去大部分乳牙之前发布,并且在您编写此答案的原始版本之前将近十年。
P
Puddle
import os, time, datetime

file = "somefile.txt"
print(file)

print("Modified")
print(os.stat(file)[-2])
print(os.stat(file).st_mtime)
print(os.path.getmtime(file))

print()

print("Created")
print(os.stat(file)[-1])
print(os.stat(file).st_ctime)
print(os.path.getctime(file))

print()

modified = os.path.getmtime(file)
print("Date modified: "+time.ctime(modified))
print("Date modified:",datetime.datetime.fromtimestamp(modified))
year,month,day,hour,minute,second=time.localtime(modified)[:-3]
print("Date modified: %02d/%02d/%d %02d:%02d:%02d"%(day,month,year,hour,minute,second))

print()

created = os.path.getctime(file)
print("Date created: "+time.ctime(created))
print("Date created:",datetime.datetime.fromtimestamp(created))
year,month,day,hour,minute,second=time.localtime(created)[:-3]
print("Date created: %02d/%02d/%d %02d:%02d:%02d"%(day,month,year,hour,minute,second))

印刷

somefile.txt
Modified
1429613446
1429613446.0
1429613446.0

Created
1517491049
1517491049.28306
1517491049.28306

Date modified: Tue Apr 21 11:50:46 2015
Date modified: 2015-04-21 11:50:46
Date modified: 21/04/2015 11:50:46

Date created: Thu Feb  1 13:17:29 2018
Date created: 2018-02-01 13:17:29.283060
Date created: 01/02/2018 13:17:29

注意:Linux 上文件的 ctime 与 Windows 上的略有不同。 Windows 用户将其称为“创建时间”。 Linux 用户将他们称为“更改时间”。


@ntninja 你确定吗?我只使用 Windows,这绝对有效。我在 2015 年初编写了这个脚本。我发现它比这里的其他脚本更清晰、直截了当、完整且不言自明。 (我碰巧决定在这里查找而不是我的旧脚本,以防万一有任何新内容。不……这就是方式)
哦,我的意思是说“......这不会给你文件的创建时间,除非你在 Windows 上”。对不起!事实仍然是这个答案是不可移植的,也没有提到这个事实。 (Linux 上的示例输出:pastebin.com/50r5vGBE
已经在这里留下了一些其他评论,我很快就会发布一个适用于(最近的)Linux 的答案。但实际上,您的帖子中唯一的错误是它是仅 Windows 的答案,没有提及这一事实。在问题中,OP 甚至专门要求提供 Windows 和 Linux 兼容的解决方案。因此,我认为如果您在顶部某处添加此“详细信息”会非常有帮助,这样人们就不会误以为 ctime 是他们在针对多个平台时正在寻找的东西。
@ntninja 我刚刚意识到你在 ctime 上责怪我(和其他人)是错误的。您真正要指出的是,Linux 上的文件 ctime 与 Windows 上的略有不同。但是,如果您正在为 linux 用户编程,那么无论如何您都不会尝试从 Windows 角度提供信息。同样,您不会尝试为 Windows 用户提供等效的 linux。这就像抱怨你不能在 linux 上打开 cmd,它会打开它的版本。大声笑(当然,这样的跨平台功能甚至存在是有原因的)但除此之外,无论如何,mtime 对任何人来说都是最重要的。
它在 Windows 和 Unix 上并没有“略微不同”——它完全不同:除非您手动更新值,否则在 Windows 上 ctime <= mtime 始终保持不变,而在 Unix 上mtime <= ctime 始终保持不变持有。您的回答表明 ctime 是文件的“创建日期”,但没有任何建议表明这根本不能移植。如果您将其称为“创建日期(在 Windows 上)”或在顶部说“此答案仅适用于 Windows”,那将是非常不同的,但这不是您在(仍然赞赏)更新答案后所做的事情。
C
Community

获取 mod 时间有两种方法,os.path.getmtime() 或 os.stat(),但 ctime 跨平台不可靠(见下文)。

os.path.getmtime()

getmtime(path) 返回上次修改路径的时间。返回值是一个数字,给出自纪元以来的秒数(参见时间模块)。如果文件不存在或不可访问,则引发 os.error。版本 1.5.2 中的新功能。在 2.3 版更改: 如果 os.stat_float_times() 返回 True,则结果为浮点数。

os.stat()

stat(path) 在给定路径上执行 stat() 系统调用。返回值是一个对象,其属性对应于stat结构的成员,即:st_mode(保护位),st_ino(inode编号),st_dev(设备),st_nlink(硬链接数),st_uid(所有者的用户ID) )、st_gid(所有者的组 ID)、st_size(文件大小,以字节为单位)、st_atime(最近访问时间)、st_mtime(最近内容修改时间)、st_ctime(平台相关;最近元数据更改时间在 Unix 上,或在 Windows 上创建时间):

>>> import os
>>> statinfo = os.stat('somefile.txt')
>>> statinfo
(33188, 422511L, 769L, 1, 1032, 100, 926L, 1105022698,1105022732, 1105022732)
>>> statinfo.st_size
926L
>>> 

在上面的示例中,您将使用 statinfo.st_mtime 或 statinfo.st_ctime 分别获取 mtime 和 ctime。


M
Mr_and_Mrs_D

os.stat 返回具有 st_mtimest_ctime 属性的命名元组。两个平台的修改时间都是st_mtime;不幸的是,在 Windows 上,ctime 表示“创建时间”,而在 POSIX 上表示“更改时间”。我不知道有什么方法可以在 POSIX 平台上获得创建时间。


以下是有关标记元组的更多信息:stackoverflow.com/questions/2970608/… 它们的工作方式与元组类似,但请尝试将 dir(..) 放在一个上。例如dir(os.stat(os.listdir('.')[0]))
D
Delgan

可能值得一看 crtime 库,它实现了对文件创建时间的跨平台访问。

from crtime import get_crtimes_in_dir

for fname, date in get_crtimes_in_dir(".", raise_on_error=True, as_epoch=False):
    print(fname, date)
    # file_a.py Mon Mar 18 20:51:18 CET 2019

我强烈建议不要这样做:它在 Linux 上使用 debugfs,这在定义上是不稳定的,需要对所有内容进行顶级 root 访问,并且在几乎所有方面往往是你母亲一直警告你的事情之一。 (但是,是的,如果您真的很绝望并且碰巧是没有安全启动的系统上的真正超级用户,它可能会起作用......)
@ntninja 我可能也永远不会在生产中使用,但它可能对“家庭脚本”有用。
是的,同意了。我为真正绝望的人创造了这个。
u
unmounted
>>> import os
>>> os.stat('feedparser.py').st_mtime
1136961142.0
>>> os.stat('feedparser.py').st_ctime
1222664012.233
>>> 

-1:正如在其他地方提到的,这不会给你文件的创建时间,除非你在 Windows 上(答案甚至没有提到!)。
一个解释将是有序的。例如,我们看到了什么?结果告诉我们什么?结论是什么?这是在哪个平台上测试的?什么版本的 Python 和库?您可以链接到已使用属性的文档吗?
P
Peter Mortensen

如果以下符号链接不重要,您还可以使用 os.lstat 内置。

>>> os.lstat("2048.py")
posix.stat_result(st_mode=33188, st_ino=4172202, st_dev=16777218L, st_nlink=1, st_uid=501, st_gid=20, st_size=2078, st_atime=1423378041, st_mtime=1423377552, st_ctime=1423377553)
>>> os.lstat("2048.py").st_atime
1423378041.0

这将给出最后读取的时间(至少在 Unix 上),这绝对不是所要求的。
“...符号链接不重要”是什么意思?你能详细说明吗?
R
Rod

os.stat 包含创建时间。对于包含时间的 os.stat() 元素,没有 st_anything 的定义。

所以试试这个:

os.stat('feedparser.py')[8]

将其与您在 ls -lah 中的文件上的创建日期进行比较

他们应该是一样的。


错误的! os.stat('feedparser.py')[8] 指的是 st_mtime,而不是创建时间。请参阅文档:docs.python.org/library/os.html#os.stat
请使用 .st_ctime 而不是丑陋的数字 [8]。