仅对文件/文件夹名称比较目录,输出差异?
我想知道怎么递归地比较两个文件夹(比较只基于文件名),并打印出只在一个文件夹里存在的文件或文件夹。
我现在使用的是Python 3.3。
我看到过filecmp
这个模块,但它似乎不能完全满足我的需求。最重要的是,它比较文件时考虑的不仅仅是文件名。
这是我目前的代码:
import filecmp
dcmp = filecmp.dircmp('./dir1', './dir2')
dcmp.report_full_closure()
dir1
的内容是这样的:
dir1
- atextfile.txt
- anotherfile.xml
- afolder
- testscript.py
- anotherfolder
- file.txt
- athirdfolder
而dir2
的内容是这样的:
dir2
- atextfile.txt
- afolder
- testscript.py
- anotherfolder
- file.txt
- file2.txt
我希望结果看起来像这样:
files/folders only in dir1
* anotherfile.xml
* athirdfolder
files/folders only in dir2
* anotherfolder/file2.txt
我需要一个简单的Python方法,只根据文件或文件夹的名称来比较两个目录,并打印出它们的不同之处。
另外,我还需要一种方法来检查这两个目录是否完全相同。
注意:我在StackOverflow和谷歌上搜索过类似的内容。我看到很多例子是比较文件内容的,但我找不到只比较文件名的例子。
4 个回答
1
其实,filecmp
这个工具可以用来做这个事情,而且应该用,但你需要写一点代码。
- 你需要给
filecmp.dircmp()
两个文件夹,一个叫左边,一个叫右边。 filecmp.dircmp.left_only
会列出只在左边文件夹里的文件和文件夹。filecmp.dircmp.right_only
会列出只在右边文件夹里的文件和文件夹。filecmp.dircmp.common_dirs
会列出两个文件夹都有的文件夹。
你可以用这些信息来写一个简单的递归函数,找出两个文件夹中不相同的文件和文件夹。
代码:
from os.path import join
from filecmp import dircmp
def find_uncommon(L_dir, R_dir):
dcmp = dircmp(L_dir, R_dir)
L_only = [join(L_dir, f) for f in dcmp.left_only]
R_only = [join(R_dir, f) for f in dcmp.right_only]
for sub_dir in dcmp.common_dirs:
new_L, new_R = find_uncommon(join(L_dir, sub_dir), join(R_dir, sub_dir))
L_only.extend(new_L)
R_only.extend(new_R)
return L_only, R_only
测试案例:
C:/
L_dir/
file_in_both_trees.txt
file_in_L_tree.txt
dir_in_L_tree/
dir_in_both_trees/
file_in_both_trees.txt
file_in_L_tree.txt
dir_in_L_tree/
file_inside_dir_only_in_L_tree.txt
R_dir/
file_in_both_trees.txt
file_in_R_tree.txt
dir_in_R_tree/
dir_in_both_trees/
file_in_both_trees.txt
file_in_R_tree.txt
dir_in_R_tree/
file_inside_dir_only_in_R_tree.txt
演示:
L_only, R_only = find_uncommon('C:\\L_dir', 'C:\\R_dir')
print('Left only:\n\t' + '\n\t'.join(L_only))
print('Right only:\n\t' + '\n\t'.join(R_only))
结果:
Left_only:
C:\L_dir\file_in_L_tree.txt
C:\L_dir\dir_in_L_tree
C:\L_dir\dir_in_both_trees\file_in_L_tree.txt
C:\L_dir\dir_in_both_trees\dir_in_L_tree
Right_only:
C:\R_dir\file_in_R_tree.txt
C:\L_dir\dir_in_R_tree
C:\R_dir\dir_in_both_trees\file_in_R_tree.txt
C:\R_dir\dir_in_both_trees\dir_in_R_tree
注意,如果你想查看那些不常见的文件夹里的内容,你需要稍微修改一下上面的代码。我说的就是我上面例子中的这两个文件:
file_inside_dir_only_in_L_tree.txt
file_inside_dir_only_in_R_tree.txt
1
基本的想法是,使用os.walk这个方法来填充文件名的字典,然后对比这些字典。
import os
from os.path import join
fpa = {}
for root, dirs, files in os.walk('/your/path'):
for name in files:
fpa[name] = 1
fpb = {}
for root, dirs, files in os.walk('/your/path2'):
for name in files:
fpb[name] = 1
print "files only in a"
for name in fpa.keys():
if not(name in fpb.keys()):
print name,"\n"
print "files only in b"
for name in fpb.keys():
if not(name in fpa.keys()):
print name,"\n"
我没有测试过这个,所以你可能需要自己修正一下。另外,这个方法也可以很容易地进行改进,以避免重复使用。
7
我的解决方案使用了set()这种类型来存储相对路径。然后比较的时候只需要进行集合的减法运算。
import os
import re
def build_files_set(rootdir):
root_to_subtract = re.compile(r'^.*?' + rootdir + r'[\\/]{0,1}')
files_set = set()
for (dirpath, dirnames, filenames) in os.walk(rootdir):
for filename in filenames + dirnames:
full_path = os.path.join(dirpath, filename)
relative_path = root_to_subtract.sub('', full_path, count=1)
files_set.add(relative_path)
return files_set
def compare_directories(dir1, dir2):
files_set1 = build_files_set(dir1)
files_set2 = build_files_set(dir2)
return (files_set1 - files_set2, files_set2 - files_set1)
if __name__ == '__main__':
dir1 = 'old'
dir2 = 'new'
in_dir1, in_dir2 = compare_directories(dir1, dir2)
print '\nFiles only in {}:'.format(dir1)
for relative_path in in_dir1:
print '* {0}'.format(relative_path)
print '\nFiles only in {}:'.format(dir2)
for relative_path in in_dir2:
print '* {0}'.format(relative_path)
讨论
主要的功能是build_files_set()这个函数。它会遍历一个目录,并创建一个包含相对文件和目录名称的集合。
compare_directories()这个函数接收两个文件集合,并返回它们之间的差异——非常简单明了。