Amazon S3 将目录复制到另一个目录

Posted

技术标签:

【中文标题】Amazon S3 将目录复制到另一个目录【英文标题】:Amazon S3 copy the directory to another directory 【发布时间】:2012-09-13 04:01:20 【问题描述】:

如何使用 php API 将包含子文件夹和文件的文件夹复制/复制到 S3 存储桶内的另一个目录中?

$s3->copy_object只复制文件夹,不复制里面的文件和子文件夹。

我是否必须使用$s3->list_objects 来获取所有文件和目录并在每个文件/目录上运行$s3->copy_object

【问题讨论】:

+1 表示问题。人们可能理解也可能不理解资源路径 S3 的概念,但请求是完全有效的。也许问题是 S3 是否支持在内部复制资源(或为同一资源创建多个路径,为什么不支持?)以某种方式?如果有很多文件,必须全部下载并重新上传真的很荒谬...... 【参考方案1】:

使用@aws-sdk/client-s3,这里是完整的js代码:

import 
    S3Client,
    CopyObjectCommandInput,
    CopyObjectCommand,
    ListObjectsCommandInput,
    ListObjectsCommand
 from '@aws-sdk/client-s3';
  
const s3Client = new S3Client( region: 'us-east-1' );

const listS3Objects = async (input: ListObjectsCommandInput) => 
     const command = new ListObjectsCommand(input);
     return await s3Client.send(command);


const copyS3Object = async (input: any) => 
    const command = new CopyObjectCommand(input);
    return await s3Client.send(command);
;

export const copyFolder = async (fromBucket:string, fromFolderKey:string, toBucket:string, toFolderKey: any) => 
      
try 
    const listObjectsResponse = await listS3Objects(
        Bucket: fromBucket,
        Prefix: `$fromFolderKey/`
    )

    const fromObjectKeys = listObjectsResponse.Contents.map(content => content.Key)

    for (let fromObjectKey of fromObjectKeys) 
        const toObjectKey = fromObjectKey.replace(fromFolderKey, toFolderKey);

       await copyS3Object(
          Bucket: toBucket,
          CopySource: `$fromBucket/$fromObjectKey`,
          Key: toObjectKey,
       )
    
   catch (error) 
     throw new Error(error)
  

【讨论】:

【参考方案2】:

对于那些寻找使用 aws sdk 的 java 解决方案的人:

public static void copyAllFilesWithPrefix(AmazonS3 s3Client,
                                          String srcBucket,
                                          String srcPrefix,
                                          String destBucket,
                                          String destPrefix) 
    ObjectListing objectListing = s3Client.listObjects(srcBucket, srcPrefix);
    for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) 
        S3Object srcFile = s3Client.getObject(srcBucket, objectSummary.getKey());
        String destKey = srcFile.getKey().replace(srcPrefix, destPrefix);
        if (!s3Client.doesObjectExist(destBucket, destKey)) 
            copyFile(s3Client, srcFile, destBucket, srcFile.getKey().replace(srcPrefix, destPrefix));
        
    

【讨论】:

【参考方案3】:

scala 代码(在一个存储桶中的文件夹之间复制):

def copyFolders(bucketName: String, srcFolder: String, targetFolder: String): Unit = 
import scala.collection.JavaConversions._
val transferManager: TransferManager = TransferManagerBuilder.standard.build
try 

  for (file <- s3.listObjects(bucketName, s"$srcFolder/").getObjectSummaries) 
    val fileName = file.getKey.replace(s"$srcFolder/", "")
    if (!fileName.isEmpty) 
      val transferProcess: Copy = transferManager.copy(bucketName, file.getKey,
        bucketName, s"$targetFolder/$fileName")
      log.info(s"Old key = $file.getKey")
      log.info(s"New file Key = $targetFolder/$fileName")
      transferProcess.waitForCompletion()
    
  
 catch 
  case e: AmazonServiceException =>
    log.error(e.getErrorMessage, e)
    System.exit(1)
  case e: AmazonClientException =>
    log.error("Amazon client error: " + e.getMessage, e)
    System.exit(1)
  case e: InterruptedException =>
    log.error("Transfer interrupted: " + e.getMessage, e)
    System.exit(1)


用法:

copyFolders("mybucket", "somefolder/srcfolder", "somefolder/targetfolder")

【讨论】:

【参考方案4】:

这里有一些直接取自亚马逊的代码。此代码将项目 a 复制到目标 3 次,您需要做的是更改它,以便循环遍历每个键并将其添加到批处理中。

<?php

// Include the AWS SDK using the Composer autoloader.
require 'vendor/autoload.php';

use Aws\S3\S3Client;

$sourceBucket = '*** Your Source Bucket Name ***';
$sourceKeyname = '*** Your Source Object Key ***';
$targetBucket = '*** Your Target Bucket Name ***';

// Instantiate the client.
$s3 = S3Client::factory();

// Copy an object.
$s3->copyObject(array(
    'Bucket'     => $targetBucket,
    'Key'        => "$sourceKeyname-copy",
    'CopySource' => "$sourceBucket/$sourceKeyname",
));

// Perform a batch of CopyObject operations.
$batch = array();
for ($i = 1; $i <= 3; $i++) 
    $batch[] = $s3->getCommand('CopyObject', array(
        'Bucket'     => $targetBucket,
        'Key'        => "$sourceKeyname-copy-$i",
        'CopySource' => "$sourceBucket/$sourceKeyname",
    ));

try 
    $successful = $s3->execute($batch);
    $failed = array();
 catch (\Guzzle\Service\Exception\CommandTransferException $e) 
    $successful = $e->getSuccessfulCommands();
    $failed = $e->getFailedCommands();

【讨论】:

【参考方案5】:

S3 不是一个文件系统,它是一个对象存储。文件夹实际上并不存在于任何有形的意义上。文件夹只是您可以称为共享前缀的东西。换句话说,如果您创建path/to/onepath/to/two,它也不会导致pathpath/to 存在。如果您看到它们,那是因为某些组件获取了一个对象列表,在 / 上拆分了它们的键,并决定将该列表显示为层次结构。

您想“将一个文件夹复制到另一个文件夹中”。将其重新表述为 S3 术语,您希望“将具有相同前缀的所有对象复制到具有不同前缀的对象中”。这么说就清楚了方法:获取带有一个前缀的对象列表,然后复制它们中的每一个。

【讨论】:

然而 aws s3 cp -R 设法在一个命令中完成它【参考方案6】:

一种方法是使用列表对象并逐个移动每个对象。另一种方法是使用 s3fuse,它将您的 s3 存储桶作为本地目录,然后您可以应用简单的命令(如“mv”)来移动文件。

【讨论】:

以上是关于Amazon S3 将目录复制到另一个目录的主要内容,如果未能解决你的问题,请参考以下文章

如何使用适用于 Node.js 的 AWS 开发工具包将 Amazon S3 中的所有对象从一个前缀复制/移动到另一个前缀

如何将文件从 S3 复制到 Amazon EMR HDFS?

将数据从 Amazon S3 复制到 Redshift 并避免重复行

将所有文件从 Amazon S3 存储桶复制到 Microsoft Azure 容器的最佳方法

将dynamoDB表复制到另一个没有S3的aws帐户

linux 怎样复制一个目录的所有文件到另一个目录