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
后时间戳不相等?
print
rounds 默认浮动?!
【问题讨论】:
无法在 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)后文件修改时间不等的主要内容,如果未能解决你的问题,请参考以下文章