Python · Google Drive ↔ OneDrive · 开源工程指南

使用 Python 构建安全的 Google Drive–OneDrive 传输工具

本指南将看似简单、实则困难的云端复制明确拆分为一套流程:枚举、预检、暂存、计算哈希、上传、重新下载、比较、保存检查点,最后才释放本地磁盘空间。

更新日期 ; 22 分钟读完.

简短回答

对于托管式迁移,FileArk 可自动执行此工作流,而无需让您的计算机充当数据传输通道。它已经过数 TB 迁移工作负载的测试,并会在报告成功前检查源文件接收情况、云服务商是否接受上传以及目标对象。如果您需要自行运行传输管道,下方采用 MIT 许可证的 Python 程序可通过您的计算机谨慎地执行复制,并且绝不会删除源文件。

先选择运行模式,再选择代码

当文件库规模较大、传输必须无人值守运行,或不应让笔记本电脑承载数据时,直接云迁移服务是更实用的选择。FileArk 可让传输持续在线运行、监控云服务商响应、重试可恢复的故障,并提供统一的进度视图。在将文件视为已完成之前,其验证流程会执行三项相互独立的检查。

如果您需要完全掌控 OAuth 应用、暂存磁盘、日志或目标文件夹策略,本地脚本会很实用。相应的代价是您必须承担运维责任:计算机必须保持在线,其网络连接会成为瓶颈,OAuth 凭据必须妥善保护,并且需要为当前批次和验证副本保留足够的临时磁盘空间。

此处发布的程序在设计上刻意采取保守策略。它从一个个人云盘的根目录复制到新的目标文件夹。程序不提供删除方法,不会覆盖冲突项;验证后会保存持久化检查点,并在本地或目标容量低于您配置的预留量时停止。

传输管道及其故障边界

  1. 盘点源目录树

    源适配器会递归遍历文件夹、按提供商的分页机制获取数据,记录 ID、路径、类型和报告的大小,并将受支持的 Google 原生文件映射为可移植的导出格式。

  2. 预检目标位置和本地容量

    引擎会将待处理字节数加上可配置的预留量,与目标配额进行比较。它还会在每个批次和每次单独下载前检查暂存文件系统。

  3. 暂存受限批次

    文件会按批次处理,每批同时受总字节数和文件数量限制。只有当前批次会占用本地磁盘,因此即使文件库很大,也不需要容量与其相同的本地磁盘。

  4. 计算哈希并上传

    下载后,脚本会计算本地 SHA-256、核对已知的源文件大小、创建目标文件夹,并使用提供商兼容的可恢复分块上传文件。

  5. 验证并保存检查点

    默认模式会重新下载新生成的目标对象并比较 SHA-256。只有匹配的文件才会写入 JSON 检查点,并从本地暂存区中移除。

下载采用 MIT 许可证的完整 Python 版本

下载内容是一个易于阅读的单文件 Python 入口程序。仅在执行实际传输时才会导入提供商 SDK,因此在安装依赖项或配置凭据之前也能运行演示和帮助命令。单独的依赖项文件会锁定最低支持的软件包版本,许可证则与源代码一并提供。

使用前请阅读代码,先用一个较小的目标文件夹进行测试,并对重要数据保留默认的重新下载验证。任何通用脚本都无法完整复现所有共享权限、快捷方式、保留标签、共享云端硬盘规则或租户策略。

下载 Python 传输程序
直接使用 Google Drive API 和 Microsoft Graph 实现,支持分批处理、检查点、重试、配额预留和目标端 SHA-256 验证。
fileark-cloud-transfer.py · Python 3.10+ · MIT 许可证

下载 Python 依赖项文件
精简的依赖项列表,用于 Google OAuth 和 Drive、Microsoft 身份验证、Graph 请求以及重试支持。
requirements-fileark-cloud-transfer.txt · pip 依赖项 · 纯文本

下载 MIT 许可证
适用于两个 FileArk 手动传输脚本的许可声明。
LICENSE-fileark-cloud-transfer.txt · MIT · 纯文本

授予云端访问权限前,先了解安全流程

终端正在以无需网络的演示模式运行 FileArk Python 云端传输脚本
内置演示无需凭据或网络调用,即可展示面向操作者的流程。实际运行时会输出相同的容量、批次、验证、检查点和源文件删除状态。

请先运行演示。它不会发起网络调用,也不会向云端写入数据。最后一行特意采用明确无歧义的表述:删除的源文件数量为零。实际引擎会通过结构化日志输出相同的流程,并在遇到第一个未通过验证的文件时以非零状态码退出。

无需网络的冒烟测试
chmod +x fileark-cloud-transfer.py
python3 fileark-cloud-transfer.py --demo
python3 fileark-cloud-transfer.py --help

创建 OAuth 客户端且不在代码中嵌入密钥

对于 Google Drive,请在 Google Cloud 项目中创建桌面 OAuth 客户端,启用 Drive API,配置同意屏幕,然后下载客户端 JSON。使用 --google-client-secret 传入其路径,或设置 GOOGLE_OAUTH_CLIENT_SECRET_FILE。脚本需要列出、下载和验证文件,以及创建文件夹和上传文件,因此会请求 Drive 访问权限。

对于 OneDrive,请在 Microsoft Entra ID 中注册公共客户端应用程序,启用设备代码流,添加委托的 Files.ReadWrite 权限,并传入应用程序客户端 ID。对于个人账户和组织账户,请选择 common;对于工作账户,请选择 organizations;如果政策要求使用特定租户,请选择相应的租户 ID。

令牌会缓存在本地文件中,使中断的迁移无需重新登录即可恢复。请将客户端 JSON 和令牌缓存视为机密信息:不要将其纳入版本控制,限制文件系统权限,切勿将其上传到支持工单,并在迁移验收后将其删除。

在隔离环境中安装依赖项
python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements-fileark-cloud-transfer.txt

从 Google Drive 传输到 OneDrive,或反向传输

所有与身份相关的值均由操作者提供。程序不附带任何客户端 ID、密钥、租户、令牌、远程账户或目标位置凭据。第一条命令会在浏览器中登录 Google,并使用设备代码登录 Microsoft,然后将文件复制到一个新的 OneDrive 文件夹。

调换源和目标即可从 OneDrive 传输到 Google Drive。每项独立迁移都应使用不同的状态文件和目标根目录。检查点会绑定源提供商、目标提供商和根目录,并拒绝使用不匹配的配置恢复迁移。

使用 8 GiB 批次从 Google Drive 传输到 OneDrive
export MICROSOFT_CLIENT_ID="your-public-client-id"
python fileark-cloud-transfer.py \
  --source google \
  --destination onedrive \
  --google-client-secret ./client_secret.json \
  --microsoft-tenant common \
  --destination-root "FileArk Manual Transfer 2026-07-25" \
  --batch-gib 8 \
  --batch-files 200 \
  --local-reserve-gib 15 \
  --destination-reserve-gib 10 \
  --verification redownload
反向传输:从 OneDrive 到 Google Drive
python fileark-cloud-transfer.py \
  --source onedrive \
  --destination google \
  --microsoft-client-id "$MICROSOFT_CLIENT_ID" \
  --google-client-secret ./client_secret.json \
  --destination-root "OneDrive archive 2026-07-25" \
  --state-file ./onedrive-to-google-state.json \
  --verification redownload

为什么要多次检查容量

在长时间传输过程中,单次预检的结果可能会失效。其他人可能向目标位置上传文件,导出的 Google 文档可能比其源元数据显示的更大,无关应用程序也可能占用本地磁盘空间。因此,引擎会在开始前检查目标位置的总容量,在每个批次检查目标容量,每次下载到本地后再次检查目标容量,并在每次暂存或复制验证文件前检查本地磁盘空间。

预留值是为运行留出的余量,并非传输大小的估算值。预留空间应足以应对操作系统更新、云服务商计量延迟,以及同一云存储配额的其他使用者。当云服务商未提供有限的剩余配额时,脚本会发出警告并依赖服务商强制执行配额;这种方式不如已知容量的预检可靠,需要主动监控。

配额检查失败即停止的不变量
def ensure_destination_capacity(quota, required, reserve):
    if quota.remaining is None:
        LOG.warning("Destination did not report a finite quota")
        return
    needed = required + reserve
    if quota.remaining < needed:
        raise RuntimeError(
            f"Destination is too small: {human_bytes(quota.remaining)} free, "
            f"{human_bytes(needed)} required including reserve."
        )

按字节数和文件数量限制暂存空间占用

字节数上限用于控制磁盘占用风险;当源中包含数十万个微小对象时,文件数上限用于控制 API 和文件系统开销。大于批次上限的文件可单独作为一个批次处理,因此预留空间必须足以容纳最大的单个对象。

默认分块大小为 10 MiB。这是 Google Drive 以 256 KiB 为粒度的可恢复上传与 Microsoft Graph 要求的 320 KiB 连续分段大小的公倍数。命令行验证器会在身份验证前拒绝不兼容的分块大小。

双重限制的批次规划器
def batches(files, max_bytes, max_files):
    batch, batch_size = [], 0
    for item in files:
        planned_size = max(item.size, 1)
        if batch and (
            len(batch) >= max_files
            or batch_size + planned_size > max_bytes
        ):
            yield batch
            batch, batch_size = [], 0
        batch.append(item)
        batch_size += planned_size
    if batch:
        yield batch

以转换方式处理 Google 原生文档

Google 文档、表格、幻灯片、绘图和 Apps Script 项目并非普通的可下载字节流。Google 适配器会分别将它们导出为 DOCX、XLSX、PPTX、PNG 和 JSON,并添加可移植的文件扩展名。程序会遍历文件夹,但除非其中包含文件,否则不会将其作为空对象上传。

转换可能会改变字体、公式、评论、嵌入对象、页面布局和协作历史记录。Google 导出端点也会施加格式和大小限制。对于不受支持的原生类型,脚本会发出警告并跳过,而不会自行创建替代格式。请手动检查具有代表性的转换后文件。

快捷方式、共享云端硬盘、与您共享但不在“我的云端硬盘”中的文件、OneNote 包、组织保留元数据、版本历史记录和共享 ACL 均不在此版本的支持范围内。正因存在这些边界,文件复制不应被称为完整的租户迁移。

通过完整重新下载目标文件来验证字节完全一致

云服务商确认上传成功是必要条件,但还不够。上传后,脚本会先比较目标位置元数据中的大小与暂存文件的大小。在默认的重新下载模式下,脚本随后会将目标对象下载到同一目录中的临时文件,计算 SHA-256,并将该摘要与暂存源文件的摘要进行比较。

只有大小和摘要均匹配时,才会生成检查点记录。检查点会记录源 ID、源报告的大小、目标 ID、目标路径、实际字节数、两份摘要以及 UTC 完成时间。如果已记录到检查点的源路径后来指向不同的 ID 或大小,脚本会停止,而不会静默跳过已更改的数据。

重新下载会使目标端的读取流量增加一倍,并暂时需要同时容纳暂存文件和验证副本的空间。只有在了解这项成本且已有独立内容验证流程时,才应选择元数据模式。

目标文件字节验证
destination.redownload(uploaded, verification_copy)
verification_hash = sha256_file(verification_copy)
if verification_hash != local_hash:
    raise RuntimeError(
        f"SHA-256 mismatch after destination re-download: {relative!r}."
    )

state["completed"][relative] = {
    "source_id": item.id,
    "destination_id": uploaded.id,
    "bytes": actual_size,
    "sha256": local_hash,
    "destination_sha256": verification_hash,
}

恢复时不将不确定状态视为成功

程序通过临时文件和重命名操作以原子方式写入状态。只有在完成这项持久化写入后,才会从本地暂存区移除已验证的项目。重新运行完全相同的命令时,程序会跳过已记录到检查点的项目,并继续处理待传输路径。

云服务商接受上传后、检查点写入前,程序可能会崩溃。由于冲突处理策略为失败,下一次运行会在遇到目标位置中已有的该路径时停止,而不会覆盖文件或错误地宣称成功。请检查并比较该对象,然后谨慎添加一条已验证的恢复记录,或改用新的目标根目录重新开始。

对于 OAuth 过期、速率限制、临时服务器错误和分块中断,程序会在设定的次数限制内重试。身份验证失败或持续的权限错误会导致程序停止。请保留日志、检查点和暂存内容,直至查明故障原因。

执行真正的验收测试

  • 先使用一个小文件夹进行测试,其中应包含空文件、大文件、深层路径、Unicode 名称和 Google 原生文档。
  • 先运行 --dry-run,并将清单中的总字节数与提供商界面显示的数据进行比较。
  • 处理第一个生产批次时,分别监控本地可用空间和目标配额。
  • 保持启用重新下载验证,并将检查点与迁移记录一并归档。
  • 在目标位置打开具有代表性的 PDF、Office 文件、图像、视频、压缩包和转换后的原生文档。
  • 比较预期的文件夹数和文件数,调查每个被跳过或失败的项目,并使用另一个用户账号测试访问。
  • 在规定的重叠期内保持源内容不变。此脚本绝不会删除源内容。

常见问题

这个 Python 脚本会删除源文件吗?

不会。程序并未实现源文件删除功能。引擎从源位置下载文件,并将其写入单独的目标根目录;验证成功后只会移除本地的临时暂存副本。

它支持双向传输吗?

可以。将 Google Drive 或 OneDrive 设为源,并将另一个提供商设为目标。每项迁移都应使用唯一的检查点和目标根目录。

它会保留共享权限和文件历史记录吗?

不会。此版本会复制文件的当前内容和文件夹路径。共享 ACL、公开链接、版本、评论、标签、保留策略和组织特有的元数据需要另行迁移和验证。

为什么要重新下载刚上传的文件?

上传已被接受以及元数据中的大小,并不能证明能够从目标端读回完全一致的字节。重新下载模式会计算目标内容的 SHA-256,并且只有在完全匹配时才保存检查点。

这是 Google 或 Microsoft 的官方工具吗?

不是。这是由 FileArk 独立开发并根据 MIT 许可证发布的参考实现。请审查代码,使用非关键数据进行测试,并遵守提供商和您所在组织的政策。

本指南使用的官方资料

阅读指南