You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现主文件夹向子文件夹增量同步(保留子文件夹独有文件)

解决方案

核心改造点

你原有的逻辑存在一个问题:仅通过MD5判断是否同步,若不同路径的文件出现哈希碰撞,会导致应该更新的文件被漏处理。我们调整为以文件的相对路径为唯一匹配标识,仅判断同路径下的文件是否需要新增/更新,同时补充目录创建和文件复制逻辑。

完整实现代码

import os
import hashlib
import shutil

def md5_checksum(filename):
    m = hashlib.md5()
    with open(filename, 'rb') as f:
        for data in iter(lambda: f.read(1024 * 1024), b''):
            m.update(data)
    return m.hexdigest()

# 改造遍历方法,返回 {相对路径: MD5值} 的字典
def get_file_md5_map(root_dir):
    md5_map = {}
    # 直接用os.walk递归遍历目录,无需手动实现递归
    for root, _, files in os.walk(root_dir):
        for file in files:
            full_path = os.path.join(root, file)
            # 计算相对于根目录的路径,保证主/子文件夹的路径匹配
            rel_path = os.path.relpath(full_path, root_dir)
            md5_map[rel_path] = md5_checksum(full_path)
    return md5_map

local_path = r'C:\test'
incoming_path = os.path.join(local_path, 'Incoming') # 主文件夹
existing_path = os.path.join(local_path, 'Colors') # 子文件夹

# 分别获取主/子文件夹的路径-MD5映射
master_file_map = get_file_md5_map(incoming_path)
child_file_map = get_file_md5_map(existing_path)

# 筛选需要同步的文件
for rel_path, master_md5 in master_file_map.items():
    child_md5 = child_file_map.get(rel_path)
    # 子文件夹无该文件,或同路径文件MD5不一致需要更新
    if child_md5 is None or child_md5 != master_md5:
        src = os.path.join(incoming_path, rel_path)
        dst = os.path.join(existing_path, rel_path)
        # 自动创建目标路径的父目录,已存在则不报错
        os.makedirs(os.path.dirname(dst), exist_ok=True)
        # 复制文件,copy2会保留文件修改时间、权限等元数据
        shutil.copy2(src, dst)
        print(f"已同步文件: {rel_path}")

逻辑说明

  • 相对路径匹配:比如主文件夹下a/b/c.txt的相对路径是a/b/c.txt,同步到子文件夹时自动拼接为{子文件夹路径}/a/b/c.txt,保证目录结构完全一致
  • 目录自动创建:os.makedirs的exist_ok=True参数会自动创建所有不存在的父级目录,不会因为目录已存在抛出异常
  • 无删除操作:全程仅对主文件夹存在的文件做新增/覆盖,不会触碰子文件夹独有的文件,符合需求要求

内容的提问来源于stack exchange,提问作者Abhinav Dhiman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 14:45:04