说明
比较 path1、path2目录,以path1为基准,比较path2目录 的 所有子目录、子文件是否相同
- 比较子目录规则:path1 存在的目录,但 path2 不存在,将其返回
- 比较子文件规则:
- path1 存在的子文件,但 path2 不存在的,将其返回
- 如果path1和path2都有该文件,那么就比较sha512值,不相同就返回;
例子
path1 目录下:
- 有目录:a、b
- 文件:1.txt、2.txt
path2 目录下:
- 有目录:a、c
- 文件:1.txt、3.txt
返回:
- [b]
- [2.txt]
提示
比较的是 相对目录,因为要比较的是两个不同目录,如果比较绝对路径,将全都不同
代码
import os,hashlib
def diff_2path(path1 ,path2,ignores:list):
'''
以path1为基准,比较path2目录 的 所有子目录、子文件是否相同
:param path1: 源路径(全路径)
:param path2: 目标路径(全路径)
:param ignores 忽略的path1的子目录、子文件(注意是相对路径,适用于 path1 目录改动 或 改文件夹名)
:return: 返回元组,第一个是 boolean,第二个元素是list,记录不同的目录,第三个元素是list,记录不同的文件
将 path1 存在的目录,但 path2 不存在的,返回
将 path1 存在的子文件,但 path2 不存在的,返回;如果path1和path2都有该文件,那么就比较sha512值,不相同就返回;
例子:
path1 目录下,有目录:a、b,文件:1.txt、2.txt
path2 目录下,有目录:a、c,文件:1.txt、3.txt
返回:
[b]
[2.txt]
'''
path1 = os.path.normpath(path1)
path2 = os.path.normpath(path2)
# 将path1的子目录、子文件list中
files1 = []
# 要比较的目录放到该list中
dirs1 = []
# 遍历出要管理目录下的所有子文件、子文件夹
walk(path1 ,files1 ,dirs1,ignores)
# 将path2的子目录、子文件list中
files2 = []
# 要比较的目录放到该list中
dirs2 = []
# 遍历出要管理目录下的所有子文件、子文件夹
walk(path2, files2, dirs2,ignores)
# 截取相对路径
folder_name1 = os.path.basename(path1)
files1_relpath = relpath_list(files1,folder_name1)
dirs1_relpath = relpath_list(dirs1,folder_name1)
folder_name2 = os.path.basename(path2)
files2_relpath = relpath_list(files2,folder_name2)
dirs2_relpath = relpath_list(dirs2,folder_name2)
# 比较path1、path2的所有子目录-----------------------
dirs_chng = []
for item in dirs1_relpath:
if item in ignores:
continue
if item in dirs2_relpath:
pass
else:
dirs_chng.append(item)
# 比较path1、path2的所有子文件,要比较 sha512
files_chng = []
for i, item1 in enumerate(files1_relpath):
diff = True # True表示不同;False表示相同
for j, item2 in enumerate(files2_relpath):
if item1 == item2:
sha512_item1 = sha512(files1[i])
sha512_item2 = sha512(files2[j])
if sha512_item1 != sha512_item2:
diff = True
else :
diff = False
break
if diff:
files_chng.append(item1)
if len(dirs_chng) > 0 or len(files_chng) > 0:
return True ,dirs_chng ,files_chng
else:
return False ,dirs_chng ,files_chng
def walk(path,files:list,dirs:list,ignores:list):
'''
遍历文件夹、文件(不包含版本库文件件)
:param path:
:param files: 保存文件
:param dirs: 保存目录
:param ignores 忽略的path1的子目录、子文件(注意是相对路径,适用于 path1 目录改动 或 改文件夹名)
:return:
'''
path = os.path.normpath(path)
# 将 ignore 截取相对路径
current_folder = os.path.basename(path)
for item in os.scandir(path):
item_relpath = relpath(item.path, current_folder)
if item_relpath in ignores:
continue
if item.is_dir():
# print("目录:",item.path)
dirs.append(item.path)
walk(item.path,files,dirs,ignores)
elif item.is_file():
# print("文件:",item.path)
files.append(item.path)
def relpath(path,start):
'''
从start开始计算相对路径(不包含start)
替代 os.path.relpath(path[, start])
:param path:
:param start:
:return:
'''
path = os.path.normpath(path)
if start == "":
return path
# print(path)
path = path.replace("\\","/")
# print(path)
new_parts = []
parts = path.split("/")
append_tag = False
for item in parts:
if item == start:
append_tag = True
continue
if append_tag:
new_parts.append(item)
if len(new_parts) == 0:
raise ValueError("["+path+"] 不包含 ["+start+"]")
new_path = "/".join(new_parts)
new_path = os.path.normpath(new_path)
return new_path
def relpath_list(paths,start):
'''
从start开始计算相对路径(不包含start)
替代 os.path.relpath(path[, start])
:param paths: list类型,路径
:param start:
:return:
'''
ret = []
for item in paths:
rel = relpath(item,start)
ret.append(rel)
return ret
def sha512(path):
# hashlib.sha512() or hashlib.md5()
algorithm = hashlib.sha512()
with open(path, 'rb') as f:
algorithm.update(f.read())
return algorithm.hexdigest()
if __name__ == "__main__":
path1 = r"C:\Users\mym\Desktop\重庆发票2"
path2 = r"C:\Users\mym\Desktop\重庆发票2\.fvm版本库\backup\2\data"
ignore = [r"C:\Users\mym\Desktop\重庆发票2\.fvm版本库"]
res,dirs_diff,files_diff = diff_2path(path1,path2,ignore)
print(res)
print(dirs_diff)
print(files_diff)