写在前面:
功能说明:给了两个文件夹,需要对比出两个文件夹的文件不同之处,包括前一个文件夹比后一个文件夹减少了哪些文件或子文件夹,亦或是后一个比前一个多了多少。
思路:
根据当下的要求,只是简单对比两个文件夹的文件名的异同。
说明扩展:
1、由于当前的程序只是对比了文件名相同与否,并不能保证后一个文件夹中的文件是否只是文件名相同,但是文件内容已经进行了修改。如果需要对比确保文件是否修改,可以在获取当前文件夹下文件的函数get_files里面,添加记录文件的最后修改时间,与文件名进行拼接组合成key,这样在后续两文件夹对比时也可以分离出修改时间。
2、同样地,该程序同样没有对比文件扩展名,如果需要对比不同的文件格式,方法同上,也是保留拓展名放置于key中。
import os
import shutil
import time
from collections import defaultdict
def make_dir(file_path, file_name = None):
"""
创建文件夹
:param file_path:
:return:
"""
if file_name is not None:
file_path = os.path.join(file_path, file_name)
try:
os.mkdir(file_path)
except FileExistsError:
print('文件夹已存在')
def get_files(file_path):
"""
获取当前绝对路径下的所有文件名
:param file_path: 文件夹绝对路径
:return: 记录文件的路径字典,记录文件夹的路径字典
"""
file_list = os.listdir(file_path)
# 当前文件夹下所有文件和文件夹的列表,key为文件名(不含拓展名),value为该文件的绝对路径
file_dict = defaultdict(str)
dir_dict = defaultdict(str)
for file in file_list:
# print(file)
file_item = os.path.join(file_path, file)
if os.path.isfile(file_item):
# 判断是否是文件
file_name = file.rsplit('.', 1)[0]
file_dict[file_name] = file_item
elif os.path.isdir(file_item):
file_name = file.rsplit('.', 1)[0]
dir_dict[file_name] = file_item
return file_dict, dir_dict
def move_file_to_dir(file_path, file_name, dir_path):
"""
把文件移动到文件夹下面
:param file_path:文件所处的文件夹路径
:param file_name:文件名
:param dir_path:所要移动到的目标文件夹
:return:
"""
try:
if dir_path is None or file_path is None:
return
file_name = os.path.join(file_path, file_name)
shutil.copy2(file_name, dir_path)
except Exception as e:
print("{}-->{}复制文件失败".format(file_name, dir_path))
def move_dir_to_dir(from_dir_path, to_dir_path):
"""
把文件夹移动到目标文件夹下面
:param from_dir_path:所要移动的文件夹
:param to_dir_path:目标文件夹
:return:
"""
try:
from_dir_name = from_dir_path.rsplit("\\", 1)[1]
to_dir_path = os.path.join(to_dir_path, from_dir_name)
shutil.copytree(from_dir_path, to_dir_path)
except Exception as e:
print("{}-->{}复制文件夹失败".format(from_dir_path, to_dir_path))
def del_files(file_path, file_name = None):
"""
删除文件
:param file_path:文件所处的文件夹路径
:param file_name:文件名,如果是None,则file_path需要是要删除文件的绝对路径
:return:
"""
if file_name is not None:
file_path = os.path.join(file_path, file_name)
if os.path.isfile(file_path):
# 删除文件
os.remove(file_path)
def del_dir(file_path):
"""
删除空白的文件夹
:param file_path:文件夹绝对路径
:return:
"""
judge = True
# 遍历路径下的所有文件夹和文件
for root, dirs, files in os.walk(file_path, topdown=False):
# 如果文件夹为空
if not dirs and not files and root != file_path:
# 删除该文件夹
os.rmdir(root)
judge = False
print(f"Removing empty dir {root}")
return judge
def compare_files(old_folder_path, new_folder_path, add_path, sub_path):
"""
对比两个新旧文件夹文件,注意,这里的都是文件名,需要结合路径进行拼接
:param old_folder_path:旧的文件夹绝对路径
:param new_folder_path:新的文件夹绝对路径
:return:
"""
# 定义增加的文件夹路径和减的文件夹路径
if os.path.exists(add_path):
pass
else:
make_dir(add_path)
if os.path.exists(sub_path):
pass
else:
make_dir(sub_path)
# 第一步,获取新旧文件夹中的
old_files_dict, old_dir_dict = get_files(file_path=old_folder_path)
new_files_dict, new_dir_dict = get_files(file_path=new_folder_path)
# 第二步,对比新旧文件夹中的文件列表,统计出多的文件和少的文件
add_files = set(new_files_dict.keys()) - set(old_files_dict.keys())
sub_files = set(old_files_dict.keys()) - set(new_files_dict.keys())
# 第三步,在增和减中创建当前文件夹路径,将多的文件移动到增文件夹对应中,少的放到减对应中
# 增加文件
if len(add_files) > 0:
for add_item in add_files:
add_file_item = new_files_dict.get(add_item)
move_file_to_dir(file_path=new_folder_path, file_name=add_file_item, dir_path=add_path)
# 减少文件
if len(sub_files) > 0:
for sub_item in sub_files:
sub_file_item = old_files_dict.get(sub_item)
move_file_to_dir(file_path=old_folder_path, file_name=sub_file_item, dir_path=sub_path)
# 第四步,对比多和少的文件夹,如果多的,放入增,少的放入减
add_dir = set(new_dir_dict.keys()) - set(old_dir_dict.keys())
sub_dir = set(old_dir_dict.keys()) - set(new_dir_dict.keys())
if len(add_dir) > 0:
for add_item in add_dir:
add_dir_item = new_dir_dict.get(add_item)
move_dir_to_dir(from_dir_path=add_dir_item, to_dir_path=add_path)
# 减少文件
if len(sub_dir) > 0:
for sub_item in sub_dir:
sub_dir_item = old_dir_dict.get(sub_item)
move_dir_to_dir(from_dir_path=sub_dir_item, to_dir_path=sub_path)
# 第五步,进入都有的文件夹中,继续step
both_dir_names = set(new_dir_dict.keys()) & set(old_dir_dict.keys())
for both_dir_item in both_dir_names:
add_path_new = os.path.join(add_path, both_dir_item)
sub_path_new = os.path.join(sub_path, both_dir_item)
compare_files(old_folder_path=os.path.join(old_folder_path, both_dir_item),
new_folder_path=os.path.join(new_folder_path, both_dir_item),
add_path=add_path_new, sub_path=sub_path_new)
######################
# 配置信息
######################
old_folder_path = "old_folder_path"
new_folder_path = "new_folder_path"
old_folder_name = old_folder_path.split("\\")[-1]
new_folder_name = new_folder_path.split("\\")[-1]
root_folder_path = old_folder_path.rsplit("\\", 1)[0]
# 对比结果的文件夹名
compare_file_path = "《{}》到《{}》的差异对比结果".format(old_folder_name, new_folder_name)
# 对比结果文件夹的放置路径,与新文件夹的路径平行
total_file_compare_path = os.path.join(root_folder_path, compare_file_path)
# 如果当前文件夹下有对比对比结果的文件夹,则创建的文件夹名字后缀加上当前系统时间最后四位
if os.path.exists(total_file_compare_path):
compare_file_path += str(time.time())[-4:]
total_file_compare_path = os.path.join(root_folder_path, compare_file_path)
# 文件夹的新增文件放置的文件夹路径,绝对路径
total_add_file_compare_path = os.path.join(total_file_compare_path, "新增")
# 文件夹的减少文件放置的文件夹路径,绝对路径
total_sub_file_compare_path = os.path.join(total_file_compare_path, "减少")
# 创建以上文件夹
make_dir(root_folder_path, compare_file_path)
make_dir(total_add_file_compare_path)
make_dir(total_sub_file_compare_path)
if __name__ == "__main__":
# 第一步,获取所有比较的文件
compare_files(old_folder_path=old_folder_path, new_folder_path=new_folder_path, add_path=total_add_file_compare_path, sub_path=total_sub_file_compare_path)
# 删除空的文件夹
while True:
if del_dir(total_add_file_compare_path) and del_dir(total_sub_file_compare_path):
break