Windows下调用shutil.copystat(file1, file2)后文件修改时间不等

Posted

技术标签:

【中文标题】Windows下调用shutil.copystat(file1, file2)后文件修改时间不等【英文标题】:File modification times not equal after calling shutil.copystat(file1, file2) under Windows 【发布时间】:2013-06-09 19:13:00 【问题描述】:

我使用 Python 2.7.5 运行以下代码。在 Windows 下:

import os, shutil, stat, time

with open('test.txt', 'w') as f: pass # create an arbitrary file
shutil.copy('test.txt', 'test2.txt') # copy it
shutil.copystat('test.txt', 'test2.txt') # copy its stats, too

t1 = os.lstat('test.txt').st_mtime # get the time of last modification for both files
t2 = os.lstat('test2.txt').st_mtime

print t1 # prints something like: 1371123658.54
print t2 # prints the same string, as expected: 1371123658.54
print t1 == t2 # prints False! Why?!

我希望两个时间戳 (=floats) 相等(正如它们的字符串表示所暗示的那样),那么为什么 t1 == t2 评估为 False

此外,我无法用更少的代码重现此行为,即不比较通过os.lstat 从两个不同 文件中检索到的时间戳。我有感觉,我在这里错过了一些微不足道的东西......


编辑:经过进一步测试,我注意到它确实会偶尔打印一次True,但不会超过每 10 次运行一次。


编辑 2: 正如 larsmans 所建议的:
print ("%.7f" % t1) # prints e.g. 1371126279.1365688
print ("%.7f" % t2) # prints e.g. 1371126279.1365681

这提出了两个新问题:

    为什么调用shutil.copystat后时间戳不相等? printrounds 默认浮动?!

【问题讨论】:

无法在 Debian Linux 上重现。试试print("%.7f" % t1)(t1 - t2) < 1e-4 看看“小字”是否不同。 要了解为什么 print rounds 默认会浮动,试试这个:x=10.1 (newline) print ("%.20f" % x)。这将打印出您想象中的其他内容。这是正常的,因为浮点值不能准确地表示所有小数值。不过我不知道shutil问题。 我知道二进制表示,但这里的情况不同:我们有一个值为 10.099999 的浮点数,它打印 10.1 尽管我们没有指定诸如 %.2f 这样的格式 - 所以似乎有一个隐含的四舍五入,这是我不知道的,我以前从未观察过...... 【参考方案1】:

问题在于copystat 调用期间不同格式之间的转换。这是因为 Windows 以定点十进制格式存储文件时间,而 Python 以浮点二进制格式存储它们。因此,每次在两种格式之间进行转换时,都会损失一些准确性。在copystat 通话期间:

    os.stat 的调用将Windows 格式转换为Python 的浮点格式。失去了一些准确性。 调用os.utime 更新文件时间。这会将其转换回 Windows 格式。再次丢失了一些准确性,并且文件时间不一定与第一个文件的时间相同。

当您自己致电os.lstat 时,会执行第三次不准确的转换。由于这些转换,文件时间并不完全相同。

documentation for os.utime 提到了这一点:

请注意,后续 stat() 调用可能不会返回您在此处设置的确切时间,具体取决于您的操作系统记录访问和修改时间的分辨率


关于您的第二个问题(为什么print 似乎对两者显示相同的值):将浮点值转换为带有str(f)print f 的字符串将对值进行四舍五入。要获得保证对不同浮点值唯一的值,请改用print repr(f)

【讨论】:

【参考方案2】:

尝试以浮点形式打印时差:print float.hex( t1 - t2)

结果:

0x1.0000000000000p-22
0x1.8000000000000p-21
0x0.0p+0
0x1.0000000000000p-20

我的 2cents 猜测:输出的变化来自浮点表示偏差和舍入误差。无论如何,在比较两个浮点数时,您应该始终使用 epsilon 值。

编辑:检查这个Python bug。

这是系统限制。底层文件系统支持 文件戳的纳秒分辨率,stat(2) 也支持 报告他们。但是,utimes(2) 只支持微秒 设置它们时的分辨率。

比较两个浮点数时,最好使用微秒分辨率。

【讨论】:

是的,更麻烦的是t1大于t2,而应该相反(text2比text1更新) 该错误报告是针对 Linux 系统的。 Python 的 Windows 实现没有使用utimes,所以没有这样的微秒限制。 GetFileTime(msdn.microsoft.com/en-us/library/windows/desktop/…) 的分辨率为 10 毫秒,所以我认为 Windows 上的 shutil 不能做得更好。 (我查看了 Python 代码和 lstat 调用 winapi GetFileAttributesExW ) 再次,您忽略了链接中的信息。 10 毫秒的分辨率仅适用于 FAT 文件系统上的创建时间。 NTFS 具有更高的分辨率。但分辨率是什么并不重要:不准确是由于与浮点之间的转换。如果 Python 实现直接复制了 Windows 时间而不进行转换,则无论文件系统的分辨率如何,这两个时间都是相同的。【参考方案3】:
from decimal import *
print Decimal(t1)
print Decimal(t2)

对 t1 和 t2 使用 round()

【讨论】:

以上是关于Windows下调用shutil.copystat(file1, file2)后文件修改时间不等的主要内容,如果未能解决你的问题,请参考以下文章

shutil模块

python shutil 模块

day05_05 shutil模块进行压缩

python基础学习shutil高级的文件,目录,压缩包处理模块

windows10下32位软件里调用驱动打印

windows下gethostbyname 调用失败