Tim's Blog

Tim's Blog

【Cloudflare 手记】Cloudflare R2 批量文件下载方案

2025-06-26
【Cloudflare 手记】Cloudflare R2 批量文件下载方案

本文主要介绍通过 Cloudflare Workers 获取 R2 对象列表,并使用 PowerShell 脚本批量下载文件

创建Worker项目

通过 Worker 获取指定 R2 里所有对象名,返回数组

这里直接使用 Cloudflare Dashboard 操作,点击 计算(Workers) -> Workers 和 Pages -> 点击 创建 按钮后选择 从 Hello World! 开始

doc_cloudflare17.png

按步骤部署后,需要将下面代码替换掉默认代码重新部署并绑定R2存储桶,设置名称为 BUCKET_IMAGES 。需要注意的是返回 headers 里需要明确使用 charset=utf-8

export default {
  async fetch(request, env, ctx) {
    // 列出桶内最多1000个对象(R2默认最大值)
    const list = await env.BUCKET_IMAGES.list();

    // 取出 key 数组
    const keys = list.objects.map(obj => obj.key);

    // 返回 JSON 数组 明确utf-8编码
    return new Response(JSON.stringify(keys, null, 2), {
      headers: { "Content-Type": "application/json;charset=utf-8" }
    });
  },
};

PowerShell 批量下载

通过 PowerShell 远程请求 Worker 将收到的数组类型结果逐个进行下载,如果本地存在相同命名的文件则跳过

创建一个 PowerShell 脚本文件(download.ps1为例),复制下面代码至脚本文件。需要关注以下变量:

  • logFile:日志路径。

  • workerUrl: Worker 项目的外部访问路径。

  • r2BucketName: R2 桶名。

  • baseDir:文件保存的本地目录。

# 初始化日志路径
$logFile = "download-fail.log"
if (Test-Path $logFile) {
    Remove-Item $logFile  # 每次运行清空旧日志
}

# Worker 返回文件列表的 URL
$workerUrl = "https://wk-get-filename.timoxo-9b3.workers.dev"

# R2 桶真实名字(wrangler 命令中用)
$r2BucketName = "images"

# 本地保存目录
$baseDir = "downloads"

# 创建下载目录(如果不存在)
if (-not (Test-Path $baseDir)) {
    New-Item -Path $baseDir -ItemType Directory | Out-Null
}

# 1. 访问 Worker 获取 JSON 文件列表
try {
    $response = Invoke-RestMethod -Uri $workerUrl -Method Get  #使用 Invoke-RestMethod 发送http get请求指定Url 
    # $response 应该是一个字符串数组
} catch {
   #$_ 表示错误对象 
    Write-Error "Request to Worker failed: $_"
    Add-Content -Path $logFile -Value  ("Request to Worker failed: " + $_.Exception.Message)
    exit 1
}

# 2. 遍历文件名,逐个下载
$total = $response.Count
$count = 0

foreach ($key in $response) {
    $count++

    $localPath = Join-Path $baseDir $key  #拼接路径
    $localDir = Split-Path $localPath  #获取目录

      # 如果文件已存在,跳过下载   -LiteralPath 表示原始路径,不解析成通配符
    if (Test-Path -LiteralPath $localPath) {
         Write-Host "Exists, skip: $localPath"
        continue
    }
     
    Write-Host "Downloading [$count/$total] : $key"

    # 确保目录存在
    if (-not (Test-Path $localDir)) {
        New-Item -Path $localDir -ItemType Directory | Out-Null
    }

   # 对包含空格或特殊字符的路径进行引号保护
    $safeKey = '"' + "$r2BucketName/$key" + '"'
   
 # 执行 wrangler r2 object get 命令下载文件
    $cmd = "wrangler r2 object get $safeKey --file `"$localPath`" --remote"
    try {
            Invoke-Expression $cmd
           } catch {
                   Write-Warning "Download error: $key"
                   Add-Content -Path $logFile -Value $key
    }
}

执行

PowerShell 脚本文件所在的目录下打开 PowerShell 命令行窗口并执行命令: .\download.ps1 ,最后等待下载结束~