Python3:根据文件内容递归比较两个目录
Python3: Recursively compare two directories based on file contents
我有两个包含一堆文件和子文件夹的目录。
我想检查两个目录中的文件内容是否相同(忽略文件名)。子文件夹结构也应该相同。
我查看了 filecmp.dircmp
但这没有帮助,因为它没有考虑文件内容; filecmp.dircmp()
没有 shallow=False
选项,请参阅 here。
this SO 答案中的解决方法也不起作用,因为它考虑了文件名。
进行比较的最佳方式是什么?
解决了这个问题。经过小测试后,这似乎有效,但还需要更多。同样,这可能会非常长,具体取决于文件的数量及其大小:
import filecmp
import os
from collections import defaultdict
from sys import argv
def compareDirs(d1,d2):
files1 = defaultdict(set)
files2 = defaultdict(set)
subd1 = set()
subd2 = set()
for entry in os.scandir(d1):
if entry.is_dir(): subd1.add(entry)
else: files1[os.path.getsize(entry)].add(entry)
#Collecting first to compare length since we are guessing no
#match is more likely. Can compare files directly if this is
# not true.
for entry in os.scandir(d2):
if entry.is_dir(): subd2.add(entry)
else: files2[os.path.getsize(entry)].add(entry)
#Structure not the same. Checking prior to content.
if len(subd1) != len(subd2) or len(files1) != len(files2): return False
for size in files2:
for entry in files2[size]:
for fname in files1[size]: #If size does not exist will go to else
if filecmp.cmp(fname,entry,shallow=False): break
else: return False
files1[size].remove(fname)
if not files1[size]: del files1[size]
#Missed a file
if files1: return False
#This is enough since we checked lengths - if all sd2 are matched, sd1
#will be accounted for.
for sd1 in subd1:
for sd2 in subd2:
if compareDirs(sd1,sd2): break
else: return False #Did not find a sub-directory
subd2.remove(sd2)
return True
print(compareDirs(argv[1],argv[2]))
递归进入两个目录。在第一级比较文件 - 如果不匹配则失败。然后尝试将第一个目录中的任何子目录递归地匹配到下一个目录中的任何子目录,直到所有匹配。
这是最天真的解决方案。在一般情况下,可能遍历树并且仅匹配大小和结构将是有益的。在那种情况下,函数看起来很相似,除了我们比较 getsize
而不是使用 filecmp
,并保存匹配的树结构,所以第二个 运行 会更快。
当然,如果有几个子目录具有完全相同的结构和大小,我们仍然需要比较所有匹配的可能性。
我有两个包含一堆文件和子文件夹的目录。 我想检查两个目录中的文件内容是否相同(忽略文件名)。子文件夹结构也应该相同。
我查看了 filecmp.dircmp
但这没有帮助,因为它没有考虑文件内容; filecmp.dircmp()
没有 shallow=False
选项,请参阅 here。
this SO 答案中的解决方法也不起作用,因为它考虑了文件名。
进行比较的最佳方式是什么?
解决了这个问题。经过小测试后,这似乎有效,但还需要更多。同样,这可能会非常长,具体取决于文件的数量及其大小:
import filecmp
import os
from collections import defaultdict
from sys import argv
def compareDirs(d1,d2):
files1 = defaultdict(set)
files2 = defaultdict(set)
subd1 = set()
subd2 = set()
for entry in os.scandir(d1):
if entry.is_dir(): subd1.add(entry)
else: files1[os.path.getsize(entry)].add(entry)
#Collecting first to compare length since we are guessing no
#match is more likely. Can compare files directly if this is
# not true.
for entry in os.scandir(d2):
if entry.is_dir(): subd2.add(entry)
else: files2[os.path.getsize(entry)].add(entry)
#Structure not the same. Checking prior to content.
if len(subd1) != len(subd2) or len(files1) != len(files2): return False
for size in files2:
for entry in files2[size]:
for fname in files1[size]: #If size does not exist will go to else
if filecmp.cmp(fname,entry,shallow=False): break
else: return False
files1[size].remove(fname)
if not files1[size]: del files1[size]
#Missed a file
if files1: return False
#This is enough since we checked lengths - if all sd2 are matched, sd1
#will be accounted for.
for sd1 in subd1:
for sd2 in subd2:
if compareDirs(sd1,sd2): break
else: return False #Did not find a sub-directory
subd2.remove(sd2)
return True
print(compareDirs(argv[1],argv[2]))
递归进入两个目录。在第一级比较文件 - 如果不匹配则失败。然后尝试将第一个目录中的任何子目录递归地匹配到下一个目录中的任何子目录,直到所有匹配。
这是最天真的解决方案。在一般情况下,可能遍历树并且仅匹配大小和结构将是有益的。在那种情况下,函数看起来很相似,除了我们比较 getsize
而不是使用 filecmp
,并保存匹配的树结构,所以第二个 运行 会更快。
当然,如果有几个子目录具有完全相同的结构和大小,我们仍然需要比较所有匹配的可能性。