Edited at

AWS の S3 のファイルを別の bucket にコピーする方法

More than 5 years have passed since last update.

s3のバケットの名前を変更することは出来ないので、URLをファイルアップロード後に変更する必要が出てきた場合はコピーする必要がある。しかし、S3本体ではbucketのコピーはサポートしていない。

以下のスクリプトを作ってみた。copy自体はS3側で直接送信する形になるのである程度高速ではある。

require 'right_aws'

aws_access_key_id, aws_secret_access_key = "key_id", "access_key"
old_bucket_name = 'from-bucket'
new_bucket_name = "to-bucket"

s3 = RightAws::S3.new(aws_access_key_id, aws_secret_access_key)
bucket = s3.bucket(old_bucket_name)

puts "Copy S3 files from '#{old_bucket_name}' to '#{new_bucket_name}'"

total_count = bucket.keys.count
puts "total_count: #{total_count}"

print "Are you sure? (y/N) > "
if gets.strip == 'y'
puts "Start to copy at #{Time.now}"
bucket.keys.each_with_index do |key, i|
print "\r#{i}"
s3.interface.copy(old_bucket_name, key.name, new_bucket_name, key.name)
end
end

アカウントを超えて転送する場合、権限が正しくつかない場合があるのでその対応を行ったパターン

require "rubygems"

require 'right_aws'
require "parallel"

aws_access_key_id, aws_secret_access_key = "xxx", "xxx"
new_bucket_email_address = "xxx@xxxx.com"

old_bucket_name = 'old'
new_bucket_name = "new"

s3 = RightAws::S3.new(aws_access_key_id, aws_secret_access_key)
bucket = RightAws::S3::Bucket.new(s3, old_bucket_name)

puts "Copy S3 files from '#{old_bucket_name}' to '#{new_bucket_name}'"

total_count = bucket.keys.count
puts "total_count: #{total_count}"

print "Are you sure? (y/N) > "
if gets.strip == 'y'
Parallel.each_with_index(bucket.keys, in_processes: 10) do |key, i|
print "\r#{i}: #{key}"
s3.interface.copy(old_bucket_name, key.name, new_bucket_name, key.name, :replace, {'x-amz-grant-full-control' => %!emailAddress="#{new_bucket_email_address}"!, 'x-amz-grant-read' => 'uri=http://acs.amazonaws.com/groups/global/AllUsers'})
end
end