背景
Cloudflare R2 是一个兼容 S3 的对象存储服务。虽然 Cloudflare 提供了 wrangler CLI 工具,但它不支持批量下载文件,只能下载单个文件。要批量导出 R2 存储桶中的文件,需要使用第三方工具。
官方推荐方案:使用 rclone
根据 Cloudflare 官方文档,批量操作 R2 文件的推荐方式是使用 rclone,一个开源的云存储同步工具。
完整操作步骤
第一步:安装 rclone
macOS:
bash
1
brew install rclone
Linux:
bash
1
curl https://rclone.org/install.sh | sudo bash
Windows: 从 rclone 官网 下载安装包
第二步:创建 R2 API Token
- 登录 Cloudflare Dashboard
- 进入 R2 管理页面:
https://dash.cloudflare.com/{account_id}/r2/overview - 点击右上角 “Manage R2 API Tokens”
- 点击 “Create API Token”
- 配置权限:
- Token name: 随意命名(例如:
r2-export-token) - Permissions:
- Object Read(读取对象)
- Object List(列出对象)
- Bucket scope: 选择需要访问的存储桶,或选择 “All buckets”
- Token name: 随意命名(例如:
- 点击 “Create API Token”
- 重要:复制并保存以下信息(只会显示一次):
- Access Key ID
- Secret Access Key
- Endpoint URL(通常格式为:
https://{account_id}.r2.cloudflarestorage.com)
第三步:配置 rclone
运行配置命令:
bash
1
rclone config
按照提示完成配置:
plaintext
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
1. 选择操作
n) New remote
> n
2. 输入 remote 名称
name> r2prod
3. 选择存储类型
Storage> s3
(输入数字或直接输入 s3)
4. 选择 S3 提供商
provider> Cloudflare
(选择 Cloudflare 或输入对应数字)
5. 选择认证方式
env_auth> false
(选择手动输入凭据)
6. 输入 Access Key ID
access_key_id> [粘贴你的 Access Key ID]
7. 输入 Secret Access Key
secret_access_key> [粘贴你的 Secret Access Key]
8. 区域设置
region> auto
(Cloudflare R2 使用 auto)
9. Endpoint 设置
endpoint> https://{account_id}.r2.cloudflarestorage.com
(替换 {account_id} 为你的实际 Account ID)
10. Location constraint
location_constraint>
(留空,直接回车)
11. ACL 设置
acl> private
12. 服务端加密
server_side_encryption>
(留空,直接回车)
13. 存储类别
storage_class>
(留空,直接回车)
14. 高级配置
Edit advanced config? (y/n)
> n
15. 确认配置
y) Yes this is OK (default)
> y
第四步:测试连接
验证 rclone 配置是否正确:
bash
12345
# 列出所有存储桶
rclone lsd r2prod:
# 列出特定存储桶的内容
rclone ls r2prod:your-bucket-name --max-depth 1
第五步:下载文件
基本用法
下载整个存储桶:
bash
1
rclone copy r2prod:bucket-name ./local-directory
下载特定前缀的文件:
bash
1
rclone copy r2prod:bucket-name/prefix/ ./local-directory
推荐参数
使用以下参数以获得更好的性能和用户体验:
bash
1234567
rclone copy r2prod:bucket-name/prefix/ ./output-directory \
--progress \ # 显示进度
--transfers 8 \ # 并行传输数(默认 4)
--checkers 16 \ # 并行检查数(默认 8)
--stats 2s \ # 每 2 秒更新统计
--stats-one-line \ # 单行显示统计
--s3-no-check-bucket # 跳过存储桶检查(提升性能)
常用场景
只下载新文件或已修改的文件(增量下载):
bash
1
rclone copy r2prod:bucket/path/ ./local-path --progress
同步(删除本地多余文件):
bash
1
rclone sync r2prod:bucket/path/ ./local-path --progress
⚠️ 注意:sync 会删除本地目录中不存在于 R2 的文件!
预览将要下载的文件(不实际下载):
bash
1
rclone copy r2prod:bucket/path/ ./local-path --dry-run
自动化脚本示例
创建一个便捷的导出脚本 export-r2-files.sh:
bash
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
#!/bin/bash
# 从 Cloudflare R2 批量导出文件
set -e
# 配置
REMOTE_NAME="r2prod"
BUCKET_NAME="your-bucket-name"
PREFIX="${1:-workflow-outputs/}"
OUTPUT_DIR="${2:-./r2-exports}"
echo "🚀 Starting R2 files export..."
echo "📦 Bucket: ${BUCKET_NAME}"
echo "📁 Prefix: ${PREFIX}"
echo "💾 Output: ${OUTPUT_DIR}"
echo ""
# 检查 rclone 是否安装
if ! command -v rclone &> /dev/null; then
echo "❌ rclone is not installed!"
echo "Install it with: brew install rclone"
exit 1
fi
# 检查远程是否配置
if ! rclone listremotes | grep -q "^${REMOTE_NAME}:$"; then
echo "❌ rclone remote '${REMOTE_NAME}' is not configured!"
echo "Run: rclone config"
exit 1
fi
# 创建输出目录
mkdir -p "${OUTPUT_DIR}"
# 测试连接
echo "🔗 Testing R2 connection..."
if ! rclone lsd "${REMOTE_NAME}:${BUCKET_NAME}" --max-depth 1 > /dev/null 2>&1; then
echo "❌ Failed to connect to R2 bucket"
exit 1
fi
echo "✅ Connection successful"
echo ""
# 下载文件
echo "⬇️ Downloading files from R2..."
rclone copy \
"${REMOTE_NAME}:${BUCKET_NAME}/${PREFIX}" \
"${OUTPUT_DIR}/${PREFIX}" \
--progress \
--transfers 8 \
--checkers 16 \
--stats 2s \
--stats-one-line \
--s3-no-check-bucket
echo ""
echo "✅ Export completed successfully!"
echo "📁 Files saved to: ${OUTPUT_DIR}/${PREFIX}"
使用方法:
bash
12345678910
chmod +x export-r2-files.sh
# 下载所有 workflow-outputs/ 文件
./export-r2-files.sh
# 下载特定月份的文件
./export-r2-files.sh workflow-outputs/2025-01/
# 指定输出目录
./export-r2-files.sh workflow-outputs/ ./my-exports
常见问题
Q1: 遇到 403 Access Denied 错误
原因:API Token 权限不足或配置错误
解决方法:
- 确认 API Token 有 Object Read 和 Object List 权限
- 在 rclone 命令中添加
--s3-no-check-bucket参数 - 或在 rclone config 中添加:
no_check_bucket = true
Q2: Endpoint URL 格式不正确
正确格式:https://{account_id}.r2.cloudflarestorage.com
错误示例:
- ❌
https://{account_id}.r2.cloudflarestorage.com/bucket-name(不要包含存储桶名) - ❌
https://r2.cloudflarestorage.com(缺少 account_id)
Q3: 如何找到 Account ID?
方法一:从 Cloudflare Dashboard URL 获取
- 登录后 URL 格式:
https://dash.cloudflare.com/{account_id}/...
方法二:从 R2 页面查看
- 进入 R2 管理页面,查看 Endpoint URL
Q4: rclone 速度慢怎么办?
尝试调整并行参数:
bash
1234
rclone copy r2prod:bucket/path/ ./local \
--transfers 16 \ # 增加并行传输数
--checkers 32 \ # 增加并行检查数
--buffer-size 128M # 增加缓冲区大小
Q5: 如何只下载特定文件类型?
使用 --include 或 --exclude 参数:
bash
12345678
# 只下载 .json 文件
rclone copy r2prod:bucket/ ./local --include "*.json"
# 排除 .tmp 文件
rclone copy r2prod:bucket/ ./local --exclude "*.tmp"
# 只下载图片
rclone copy r2prod:bucket/ ./local --include "*.{jpg,png,gif}"
其他可选方案
1. AWS CLI
R2 兼容 S3 API,也可以使用 AWS CLI:
bash
123456789101112
# 配置
aws configure --profile r2
# AWS Access Key ID: [R2 Access Key]
# AWS Secret Access Key: [R2 Secret Key]
# Default region name: auto
# Default output format: json
# 设置 endpoint
export AWS_ENDPOINT_URL=https://{account_id}.r2.cloudflarestorage.com
# 下载文件
aws s3 cp s3://bucket-name/path/ ./local-path/ --recursive --profile r2
2. S3-compatible GUI 工具
- Cyberduck - 免费,支持 S3
- Mountain Duck - 付费,可将 R2 挂载为本地磁盘
- S3 Browser - Windows,免费
3. 编程方式
使用 AWS SDK 访问 R2(以 Node.js 为例):
javascript
123456789101112131415161718192021222324252627
import { S3Client, ListObjectsV2Command, GetObjectCommand } from '@aws-sdk/client-s3';
const s3 = new S3Client({
region: 'auto',
endpoint: 'https://{account_id}.r2.cloudflarestorage.com',
credentials: {
accessKeyId: 'your-access-key',
secretAccessKey: 'your-secret-key',
},
});
// 列出对象
const listCommand = new ListObjectsV2Command({
Bucket: 'bucket-name',
Prefix: 'workflow-outputs/',
});
const { Contents } = await s3.send(listCommand);
// 下载文件
for (const object of Contents) {
const getCommand = new GetObjectCommand({
Bucket: 'bucket-name',
Key: object.Key,
});
const response = await s3.send(getCommand);
// 处理 response.Body
}
总结
- ✅ 推荐方案:rclone(官方推荐,稳定可靠)
- ✅ 备选方案:AWS CLI、GUI 工具、编程 SDK
- ❌ 不推荐:wrangler CLI(不支持批量操作)