用Python检测重复文件
我正在尝试用Python写一个脚本,目的是整理文件(比如照片和视频),检查每个文件的元数据,找到所有重复的文件并把它们移动到一个单独的文件夹里。不过在检查元数据的部分遇到了困难。我试过用os.stat这个方法,但它并不能正确判断重复的文件。理想情况下,我应该能做到类似这样的事情:
if os.stat("original.jpg")== os.stat("duplicate.jpg"):
shutil.copy("duplicate.jpg","C:\\Duplicate Folder")
有没有人能给点建议?
4 个回答
os.stat 可以提供一些文件的基本信息,比如创建时间。不过,单靠这些信息来判断两个文件是否相同并不是个好办法。
举个例子:两个文件可能内容完全一样,但创建时间却不同。因此,光比较这些信息是没用的。Sylvain Leroux 提出的办法在性能和准确性上是最好的,因为不同的文件有相同哈希值的情况非常少见。
所以,除非你有大量的数据,并且重复的文件会导致系统崩溃,否则这个方法是最合适的。
如果你确实面临这种情况(但看起来并不是),那么唯一能让你100%确定两个文件相同的方法就是逐字节地进行比较。
如果两个文件的 md5
值相同,那它们就是完全一样的重复文件。
from hashlib import md5
with open(file1, "r") as original:
original_md5 = md5(original.read()).hexdigest()
with open(file2, "r") as duplicate:
duplicate_md5 = md5(duplicate.read()).hexdigest()
if original_md5 == duplicate_md5:
do_stuff()
在你的例子中,你使用的是 jpg
文件,这种情况下你需要用 open
方法,并且它的第二个参数要设置为 rb
。想了解更多,可以查看 open 的文档。
你可以做几件事情。你可以比较每个文件的内容或者它们的哈希值,或者你也可以查看一些从os.stat结果中选出的特定属性,比如:
def is_duplicate(file1, file2):
stat1, stat2 = os.stat(file1), os.stat(file2)
return stat1.st_size==stat2.st_size and stat1.st_mtime==stat2.st_mtime
这是一个基本的循环,用来利用一个set
来记录已经遇到的文件:
import glob
import hashlib
uniq = set()
for fname in glob.glob('*.txt'):
with open(fname,"rb") as f:
sig = hashlib.sha256(f.read()).digest()
if sig not in uniq:
uniq.add(sig)
print fname
else:
print fname, " (duplicate)"
需要注意的是,任何哈希函数都有可能出现一点点小问题,这叫做碰撞。也就是说,可能会有两个不同的文件产生相同的哈希值。根据你的需求,这种情况可能是可以接受的,也可能不可以。
“比如说,使用SHA-256(n=256)和十亿条消息(p=109),那么发生碰撞的概率大约是4.3*10-60。”
根据你的需求,如果你需要检查其他属性来识别“真正的”重复文件,可以把sig = ....
这一行改成适合你的内容。例如,如果你需要检查“内容相同”和“拥有者相同”(st_uid
是通过os.stat()
返回的),可以这样写:
sig = ( hashlib.sha256(f.read()).digest(),
os.stat(fname).st_uid )