Python跨层级子文件夹增量备份脚本功能完善求助
问题描述
三次数据丢失后,我编写了Python脚本将电脑数据备份到外置SSD。当前脚本可正常处理源文件夹根目录的文件及文件夹,但无法检测深层子文件夹(如C:\Users\UNIX\Desktop\backup\x\w\a)内的新增或修改内容。不想因7KB的小文件改动复制100GB+的整个文件夹,附上现有代码,寻求实现仅复制子文件夹中新增或修改内容到对应目标路径的方法。
现有代码
import os, shutil import os.path, time import filecmp from filecmp import dircmp fob = open(r"C:\Users\UNIX\Desktop\backup\log.txt", "a") dir_src = r"C:\Users\UNIX\Desktop\backup\x" dir_dst = r"C:\Users\UNIX\Desktop\backup\y" left_folder = [] right_folder =[] def start_log(): fob.write("\n") fob.write("===============") fob.write("Started at: %s" % time.strftime("%c")) fob.write("\n") def write_log(): fob.write("File name: %s" % os.path.basename(pathname)) fob.write(" Last modified date: %s" %time.ctime(os.path.getmtime(pathname))) fob.write(" Copied on: %s" % time.strftime("%c")) fob.write("\n") def print_diff_files(dcmp): global name, left_folder, right_folder, left_file, right_file for name in dcmp.diff_files: left_file = f"{dcmp.left}\{name}" right_file = f"{dcmp.right}\{name}" left_folder.append(left_file) right_folder.append(right_file) for sub_dcmp in dcmp.subdirs.values(): print_diff_files(sub_dcmp) start_log() for w in os.listdir(dir_src): name = "" pathname = os.path.join(dir_src, w) try: spathname = os.path.join(dir_dst, w) if os.path.isdir(spathname): dcmp = dircmp(pathname, spathname) print_diff_files(dcmp) if name != "": for file in left_folder: shutil.copy2(left_file, right_file) write_log() print("New folder version added: " + str(pathname)) print(f"Modified files: {right_file}") elif not filecmp.cmp(pathname, spathname): shutil.copy(pathname, dir_dst) write_log() print("New file version added: " + str(spathname)) except: if os.path.isdir(pathname): shutil.copytree(pathname, spathname, dirs_exist_ok=True) write_log() print("New folder added: " + str(spathname)) else: spathname = os.path.join(dir_dst, w) shutil.copy(pathname, dir_dst) write_log() print("New file added: " + str(spathname)) fob.close() print("Done")
问题分析与修复方案
现有代码核心问题
- 变量覆盖:
print_diff_files中left_file和right_file会被循环覆盖,最终仅复制最后一个差异文件 - 日志路径错误:
write_log依赖全局pathname,无法正确传递子文件夹内的文件路径,导致日志记录错误 - 差异文件未复制:根目录遍历中的
if name != ""条件永远不成立,收集到的差异文件未执行复制操作 - 未处理新增文件:仅检测修改过的文件(
dcmp.diff_files),未处理源文件夹新增的文件/文件夹(dcmp.left_only)
修复后的代码
import os import shutil import time import filecmp from filecmp import dircmp LOG_PATH = r"C:\Users\UNIX\Desktop\backup\log.txt" DIR_SRC = r"C:\Users\UNIX\Desktop\backup\x" DIR_DST = r"C:\Users\UNIX\Desktop\backup\y" def start_log(file_obj): file_obj.write("\n") file_obj.write("===============\n") file_obj.write(f"Started at: {time.strftime('%c')}\n") def write_log(file_obj, file_path): file_name = os.path.basename(file_path) mtime = time.ctime(os.path.getmtime(file_path)) copy_time = time.strftime("%c") file_obj.write(f"File name: {file_name}\n") file_obj.write(f" Last modified date: {mtime}\n") file_obj.write(f" Copied on: {copy_time}\n") def sync_dirs(dcmp, log_file): # 处理修改过的文件 for file_name in dcmp.diff_files: src_file = os.path.join(dcmp.left, file_name) dst_file = os.path.join(dcmp.right, file_name) shutil.copy2(src_file, dst_file) write_log(log_file, src_file) print(f"Modified file copied: {dst_file}") # 处理源文件夹新增的文件/文件夹 for file_name in dcmp.left_only: src_path = os.path.join(dcmp.left, file_name) dst_path = os.path.join(dcmp.right, file_name) if os.path.isdir(src_path): shutil.copytree(src_path, dst_path, dirs_exist_ok=True) write_log(log_file, src_path) print(f"New folder added: {dst_path}") else: shutil.copy2(src_path, dst_path) write_log(log_file, src_path) print(f"New file added: {dst_path}") # 递归处理子文件夹 for sub_dcmp in dcmp.subdirs.values(): sync_dirs(sub_dcmp, log_file) def main(): with open(LOG_PATH, "a") as log_file: start_log(log_file) for item in os.listdir(DIR_SRC): src_path = os.path.join(DIR_SRC, item) dst_path = os.path.join(DIR_DST, item) try: if os.path.isdir(src_path): if os.path.exists(dst_path): # 同步已存在文件夹的差异 dcmp = dircmp(src_path, dst_path) sync_dirs(dcmp, log_file) else: # 复制新增的完整文件夹 shutil.copytree(src_path, dst_path) write_log(log_file, src_path) print(f"New folder added: {dst_path}") else: if os.path.exists(dst_path): # 检查已存在文件是否修改 if not filecmp.cmp(src_path, dst_path): shutil.copy2(src_path, dst_path) write_log(log_file, src_path) print(f"Modified file copied: {dst_path}") else: # 复制新增文件 shutil.copy2(src_path, dst_path) write_log(log_file, src_path) print(f"New file added: {dst_path}") except Exception as e: print(f"Error processing {src_path}: {str(e)}") print("Done") if __name__ == "__main__": main()
关键改动说明
- 递归同步子文件夹:
sync_dirs函数递归处理所有层级子文件夹的差异,直接在递归中完成复制和日志记录,避免全局变量问题 - 覆盖全场景:同时处理修改文件(
diff_files)和新增文件/文件夹(left_only) - 日志函数优化:传递当前文件路径作为参数,确保日志记录正确的文件信息
- 代码结构优化:使用
with语句管理日志文件,避免资源泄漏;拆分功能函数,提升可读性 - 错误处理:新增异常捕获并打印错误信息,方便排查问题
内容的提问来源于stack exchange,提问作者Catalin
相关产品推荐
相关产品推荐

