2011-03-04 78 views
67

我對s3cmd很滿意,但有一個問題:如何將所有文件從一個S3存儲桶複製到另一個存儲區?它甚至有可能嗎?是否可以使用s3cmd將所有文件從一個S3存儲桶複製到另一個S3存儲桶?

編輯:我已經找到一種方法來使用Python與博託桶之間複製文件:

from boto.s3.connection import S3Connection 

def copyBucket(srcBucketName, dstBucketName, maxKeys = 100): 
    conn = S3Connection(awsAccessKey, awsSecretKey) 

    srcBucket = conn.get_bucket(srcBucketName); 
    dstBucket = conn.get_bucket(dstBucketName); 

    resultMarker = '' 
    while True: 
    keys = srcBucket.get_all_keys(max_keys = maxKeys, marker = resultMarker) 

    for k in keys: 
     print 'Copying ' + k.key + ' from ' + srcBucketName + ' to ' + dstBucketName 

     t0 = time.clock() 
     dstBucket.copy_key(k.key, srcBucketName, k.key) 
     print time.clock() - t0, ' seconds' 

    if len(keys) < maxKeys: 
     print 'Done' 
     break 

    resultMarker = keys[maxKeys - 1].key 

此同步,幾乎是直線前進的複製。有ETag字段,大小和上次修改的鍵可用。

也許這對別人也有幫助。

+3

嘿,你可以讓你的編輯成爲答案並接受?這是一個非常有用的提示! – Hamish

+1

你使用'get_all_keys'而不是'list'的任何原因? – BillR

回答

82

s3cmd sync s3://from/this/bucket/ s3://to/this/bucket/

對於可用的選項,請使用: $s3cmd --help

+1

真棒建議。愛那s3cmd。尾隨斜線可能很重要,所以's3cmd sync s3:// sample_bucket/s3:// staging_bucket /'對我來說效果很好。 –

+0

我也不喜歡這種行爲。評論者儘量減少花費在評論上的時間,因此你的改變不僅需要保持良好,而且需要看起來如此。如果你的變化被拒絕了,但是你非常確信它確實是需要的,如果你給它下一次嘗試,我不會認爲它是不好的行爲 - 也許與其他評論者一樣,你會有更多的運氣。 – peterh

+9

你也可以使用aws cli來做到這一點。 aws s3同步s3://從/ s3://到/ – Bobo

1

s3cmd不會只帶前綴或通配符,但可以使用's3cmd ls sourceBucket'編寫腳本,awk提取對象名稱。然後使用's3cmd cp sourceBucket/name destBucket'複製列表中的每個對象名稱。

我在DOS窗口在Windows上使用這些批處理文件:

s3list.bat

s3cmd ls %1 | gawk "/s3/{ print \"\\"\"\"substr($0,index($0,\"s3://\"))\"\\"\"\"; }" 

s3copy.bat

@for /F "delims=" %%s in ('s3list %1') do @s3cmd cp %%s %2 
+0

請注意,此方法速度非常慢(與其他一次只能執行一個對象的解決方案一樣) - 但如果您沒有太多要複製的項目,它會起作用。 –

+0

這個答案很長一段時間讓我迷惑......但實際上s3cmd如果你使用了正確的(有點不直觀的)選項集,可以使用通配符。我發佈了一個答案,詳細信息。 – mdahlman

2

感謝 - 我用一個稍微修改後的版本,其中我只複製不存在或文件大小不同的文件,並檢查源文件中是否存在密鑰。我發現這是一個有點快爲準備好測試環境:

def botoSyncPath(path): 
    """ 
     Sync keys in specified path from source bucket to target bucket. 
    """ 
    try: 
     conn = S3Connection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) 
     srcBucket = conn.get_bucket(AWS_SRC_BUCKET) 
     destBucket = conn.get_bucket(AWS_DEST_BUCKET) 
     for key in srcBucket.list(path): 
      destKey = destBucket.get_key(key.name) 
      if not destKey or destKey.size != key.size: 
       key.copy(AWS_DEST_BUCKET, key.name) 

     for key in destBucket.list(path): 
      srcKey = srcBucket.get_key(key.name) 
      if not srcKey: 
       key.delete() 
    except: 
     return False 
    return True 
2

我寫了備份的S3存儲的腳本:https://github.com/roseperrone/aws-backup-rake-task

#!/usr/bin/env python 
from boto.s3.connection import S3Connection 
import re 
import datetime 
import sys 
import time 

def main(): 
    s3_ID = sys.argv[1] 
    s3_key = sys.argv[2] 
    src_bucket_name = sys.argv[3] 
    num_backup_buckets = sys.argv[4] 
    connection = S3Connection(s3_ID, s3_key) 
    delete_oldest_backup_buckets(connection, num_backup_buckets) 
    backup(connection, src_bucket_name) 

def delete_oldest_backup_buckets(connection, num_backup_buckets): 
    """Deletes the oldest backup buckets such that only the newest NUM_BACKUP_BUCKETS - 1 buckets remain.""" 
    buckets = connection.get_all_buckets() # returns a list of bucket objects 
    num_buckets = len(buckets) 

    backup_bucket_names = [] 
    for bucket in buckets: 
     if (re.search('backup-' + r'\d{4}-\d{2}-\d{2}' , bucket.name)): 
      backup_bucket_names.append(bucket.name) 

    backup_bucket_names.sort(key=lambda x: datetime.datetime.strptime(x[len('backup-'):17], '%Y-%m-%d').date()) 

    # The buckets are sorted latest to earliest, so we want to keep the last NUM_BACKUP_BUCKETS - 1 
    delete = len(backup_bucket_names) - (int(num_backup_buckets) - 1) 
    if delete <= 0: 
     return 

    for i in range(0, delete): 
     print 'Deleting the backup bucket, ' + backup_bucket_names[i] 
     connection.delete_bucket(backup_bucket_names[i]) 

def backup(connection, src_bucket_name): 
    now = datetime.datetime.now() 
    # the month and day must be zero-filled 
    new_backup_bucket_name = 'backup-' + str('%02d' % now.year) + '-' + str('%02d' % now.month) + '-' + str(now.day); 
    print "Creating new bucket " + new_backup_bucket_name 
    new_backup_bucket = connection.create_bucket(new_backup_bucket_name) 
    copy_bucket(src_bucket_name, new_backup_bucket_name, connection) 


def copy_bucket(src_bucket_name, dst_bucket_name, connection, maximum_keys = 100): 
    src_bucket = connection.get_bucket(src_bucket_name); 
    dst_bucket = connection.get_bucket(dst_bucket_name); 

    result_marker = '' 
    while True: 
     keys = src_bucket.get_all_keys(max_keys = maximum_keys, marker = result_marker) 

     for k in keys: 
      print 'Copying ' + k.key + ' from ' + src_bucket_name + ' to ' + dst_bucket_name 

      t0 = time.clock() 
      dst_bucket.copy_key(k.key, src_bucket_name, k.key) 
      print time.clock() - t0, ' seconds' 

     if len(keys) < maximum_keys: 
      print 'Done backing up.' 
      break 

     result_marker = keys[maximum_keys - 1].key 

if __name__ =='__main__':main() 

我用這個在一耙的任務(一個Rails應用程序):

desc "Back up a file onto S3" 
task :backup do 
    S3ID = "*****" 
    S3KEY = "*****" 
    SRCBUCKET = "primary-mzgd" 
    NUM_BACKUP_BUCKETS = 2 

    Dir.chdir("#{Rails.root}/lib/tasks") 
    system "./do_backup.py #{S3ID} #{S3KEY} #{SRCBUCKET} #{NUM_BACKUP_BUCKETS}" 
end 
3

它實際上是可能的。這爲我工作:

import boto 


AWS_ACCESS_KEY = 'Your access key' 
AWS_SECRET_KEY = 'Your secret key' 

conn = boto.s3.connection.S3Connection(AWS_ACCESS_KEY, AWS_SECRET_KEY) 
bucket = boto.s3.bucket.Bucket(conn, SRC_BUCKET_NAME) 

for item in bucket: 
    # Note: here you can put also a path inside the DEST_BUCKET_NAME, 
    # if you want your item to be stored inside a folder, like this: 
    # bucket.copy(DEST_BUCKET_NAME, '%s/%s' % (folder_name, item.key)) 
    bucket.copy(DEST_BUCKET_NAME, item.key) 
+0

複製方法用於'boto.s3.key'對象,[請參閱此處](http://boto.readthedocs.org/en/latest/ref/s3.html#module-boto.s3.key)。但這是直接複製/移動文件的一種好方法,不用擔心*'子文件夾'*的細節。 – GeoSharp

28

最upvotes的答案,因爲我寫這篇文章是這個:

s3cmd sync s3://from/this/bucket s3://to/this/bucket 

這是一個有用的答案。但有時同步不是你需要的(它刪除文件等)。我花了很長時間才弄清楚這個非腳本化的替代方法,只是在桶之間複製多個文件。 (好吧,如下所示,它不在桶之間,它位於非真正的文件夾之間,但它同樣適用於桶之間。)

# Slightly verbose, slightly unintuitive, very useful: 
s3cmd cp --recursive --exclude=* --include=file_prefix* s3://semarchy-inc/source1/ s3://semarchy-inc/target/ 

說明上述命令:

  • -recursive
    在我的腦海裏,我的要求是不是遞歸。我只是想要多個文件。但在這種情況下遞歸只是告訴s3cmd cp處理多個文件。大。
  • -exclude
    這是一個奇怪的方式來思考問題。以遞歸方式選擇所有文件開始。接下來,排除所有文件。等等,什麼?
  • -include
    現在我們在談論。指出要包含的文件前綴(或後綴或任何模式)。
    s3://sourceBucket/ s3://targetBucket/
    這部分足夠直觀。雖然在技術上它似乎違背了從s3cmd幫助文檔例子表明源對象必須指定:
    s3cmd cp s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]
+0

爲了讓這個好的答案很好,請複製'你的[深入的博客文章](http://mdahlman.wordpress.com/2013/12/05/copy-files-between-s3-buckets/)的啓蒙'部分到你的答案。做得好! –

+0

難道你不能達到同樣的:'s3cmd sync --max-delete = 0 s3://從s3://到'? – schmijos

+0

嗯...我從來沒有找到這個選項。所以我不能確認它是否有效。但我不明白爲什麼它不會。實際上,現在我看到'--no-delete-removed',這看起來更加重要。 – mdahlman

1

您還可以使用s3funnel它採用多線程:

https://github.com/neelakanta/s3funnel

示例(不顯示訪問密鑰或密鑰參數):

s3funnel source-bucket-name list | s3funnel dest-bucket-name copy -source-bucket source-bucket-name -threads = 10

2

mdahlman的代碼並沒有爲我工作,但在這鬥命令將在bucket1所有文件到一個新的文件夾(命令還創建這個新文件夾)2.

cp --recursive --include=file_prefix* s3://bucket1/ s3://bucket2/new_folder_name/ 
4

您也可以使用Web界面可以這樣做:

  1. 轉到源桶在網絡interfac即
  2. 標記要複製的文件(使用移位和鼠標點擊標記幾個)。
  3. 按動作 - >複製。
  4. 轉到目標存儲桶。
  5. 按操作 - >粘貼。

就是這樣。

相關問題