Bootstrap

将OneDrive上的文件定期备份到移动硬盘

背景:

我在oneDrive上存了很多文件,分布在多个文件夹中,也有套了好几层文件夹的情况。我希望每隔一段时间,将oneDrive上的所有文件向移动硬盘上拷贝一份,但是我只想将距离上一次向移动硬盘拷贝的文件相比,发生变化的一部分,也就是只拷贝距离上一次有变化(新增、删除或修改)的文件。但是每一次拷贝时,都手动将所有文件都一一比对太麻烦了,有什么办法能让我快速的将发生了变化的文件同步过去吗?。使用python,定期的同步(比如每10天),并且将每次同步在日志文件中记录下来,包括但不限于同步时间,同步的具体文件,路径等等。

一、同步文件的代码

import os
import shutil
import time
import hashlib
import logging
from datetime import datetime

# 设置日志记录
logging.basicConfig(filename='sync_log.txt', level=logging.INFO,
                    format='%(asctime)s - %(message)s')

# 配置OneDrive路径和移动硬盘路径
onedrive_path = r'E:\OneDrive\qlu\OneDrive - stu.qlu.edu.cn'
external_drive_path = r'E:\SyncOneDrive\OneDriveBak'

# 用于计算文件的哈希值
def get_file_hash(file_path):
    hash_sha256 = hashlib.sha256()
    with open(file_path, 'rb') as f:
        while chunk := f.read(8192):
            hash_sha256.update(chunk)
    return hash_sha256.hexdigest()

# 检查文件是否是云端文件
def is_cloud_file(file_path):
    # 如果文件存在但大小为0,表示是云端文件尚未下载
    return os.path.exists(file_path) and os.path.getsize(file_path) == 0

# 用于同步文件的函数
def sync_files():
    retries = 3  # 最大重试次数
    for root, dirs, files in os.walk(onedrive_path):
        for file in files:
            onedrive_file_path = os.path.join(root, file)
            relative_path = os.path.relpath(onedrive_file_path, onedrive_path)
            external_file_path = os.path.join(external_drive_path, relative_path)
            
            # 如果是云端文件(大小为0),先跳过或尝试下载
            if is_cloud_file(onedrive_file_path):
                logging.info(f"Cloud file detected, skipping download: {onedrive_file_path}")
                continue  # 跳过该文件

            # 重试逻辑
            for attempt in range(retries):
                try:
                    # 检查文件是否有修改或者不存在
                    if os.path.exists(external_file_path):
                        # 比较文件的修改时间或哈希值
                        if os.path.getmtime(onedrive_file_path) > os.path.getmtime(external_file_path):
                            shutil.copy2(onedrive_file_path, external_file_path)  # 拷贝文件
                            logging.info(f"Updated: {onedrive_file_path} -> {external_file_path}")
                        elif get_file_hash(onedrive_file_path) != get_file_hash(external_file_path):
                            shutil.copy2(onedrive_file_path, external_file_path)  # 拷贝文件
                            logging.info(f"Modified: {onedrive_file_path} -> {external_file_path}")
                    else:
                        # 如果文件在移动硬盘上不存在,直接拷贝
                        os.makedirs(os.path.dirname(external_file_path), exist_ok=True)
                        shutil.copy2(onedrive_file_path, external_file_path)
                        logging.info(f"New: {onedrive_file_path} -> {external_file_path}")
                    break  # 如果成功复制文件,则跳出重试循环
                except PermissionError as e:
                    logging.warning(f"PermissionError: {onedrive_file_path} is in use. Retrying... {attempt + 1}/{retries}")
                    time.sleep(2)  # 等待2秒后重试
                    if attempt == retries - 1:
                        logging.error(f"Failed to copy file after {retries} attempts: {onedrive_file_path}")


# 直接执行同步任务
def job():
    sync_files()
    logging.info('Sync completed.\n')

job()

二、定时触发同步

为了让Windows每隔10天自动运行你的Python脚本并确保它以管理员权限运行,你可以使用 任务计划程序 (Task Scheduler) 来实现。

2.1创建Python脚本

确保你已经将Python脚本保存好,并确认它能够正常运行(例如:syncOneDrive.py)。

2.2 打开任务计划程序

  1. 在Windows搜索框中输入“任务计划程序”,并选择“任务计划程序”应用。
  2. 在任务计划程序窗口中,选择右侧的“创建基本任务”。

2.3 创建任务

  1. 设置任务名称和描述

    • 输入任务的名称(例如:“同步OneDrive到移动硬盘”)。
    • 可选择添加描述(如:“每10天同步OneDrive上的文件到移动硬盘”)。
  2. 设置触发条件

    • 选择“每天”,然后点击“下一步”。
    • 在“设置”中,选择“重复任务每10天,并设置结束日期(例如:无限重复或设置具体的结束日期)。
  3. 设置动作

    • 选择“启动程序”,然后点击“下一步”。
    • 在“程序/脚本”框中,输入你的Python解释器的路径。例如,如果你使用的是Python 3.9:
      • C:\Users\用户名\AppData\Local\Programs\Python\Python39\python.exe
    • 在“添加参数”框中,输入你的Python脚本路径,例如:
      • E:\SyncOneDrive\syncOneDrive.py
    • 在“起始于”框中,输入Python脚本所在的文件夹路径:
      • E:\SyncOneDrive\
  4. 设置权限(管理员权限)

    • 在“完成”页之前,点击“打开高级属性”。
    • 进入“常规”选项卡,勾选“以最高权限运行”。这将确保任务以管理员权限运行。
    • 点击“确定”保存。
  5. 完成设置

    • 点击“完成”按钮,任务计划程序将会自动保存并开始工作。

2.4 确认任务

完成创建任务后,你可以在任务计划程序的任务库中看到你创建的任务。你可以右键点击它,选择“运行”来手动测试任务是否能够正常运行。

小提示:

  • 管理员权限:确保你有管理员权限运行该任务,否则你可能会遇到权限问题,特别是在访问某些目录时(如C:盘或系统目录)。
  • Python路径:确保任务计划程序中的Python路径是正确的,特别是如果你使用了虚拟环境或多个Python版本。
;