

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Amazon S3 ユーティリティ
<a name="sdk-utilities-s3"></a>

## Amazon S3 転送マネージャー
<a name="transfer-managers"></a>

 Amazon S3 のアップロードおよびダウンロードマネージャーは、大きなオブジェクトを複数のパートに分割して並列で転送できます。これにより、中断された転送を簡単に再開できます。

### Amazon S3 アップロードマネージャー
<a name="s3-upload-manager"></a>

 Amazon S3 アップロードマネージャーは、ファイルを小さなパートに分割可能かどうかを判断し、可能な場合は並列でアップロードします。並列アップロードの数とアップロードされるパートのサイズをカスタマイズできます。

 次の例では、Amazon S3 `Uploader` を使用してファイルをアップロードします。`Uploader` の使用は `s3.PutObject()` オペレーションと似ています。

```
import "context"
import "github.com/aws/aws-sdk-go-v2/config"
import "github.com/aws/aws-sdk-go-v2/service/s3"
import "github.com/aws/aws-sdk-go-v2/feature/s3/manager"

// ...

cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    log.Printf("error: %v", err)
    return
}

client := s3.NewFromConfig(cfg)

uploader := manager.NewUploader(client)
result, err := uploader.Upload(context.TODO(), &s3.PutObjectInput{
    Bucket: aws.String("amzn-s3-demo-bucket"),
    Key:    aws.String("my-object-key"),
    Body:   uploadFile,
})
```

#### 設定オプション
<a name="configuration-options"></a>

 [NewUploader](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/feature/s3/manager#NewUploader) を使用して `Uploader` インスタンスを作成する際に、アップロード方法をカスタマイズするための設定オプションを指定できます。オプションは、`NewUploader` に 1 つ以上の引数を渡すことでオーバーライドされます。オプションには以下が含まれます：
+  `PartSize` – アップロードする各パートのバッファサイズをバイト単位で指定します。パートごとの最小サイズは 5 MiB です。
+  `Concurrency` – 並行でアップロードするパートの数を指定します。
+  `LeavePartsOnError` – Amazon S3 に正常にアップロードされたパートを残すかどうかを指定します。

 `Concurrency` の値は、1 回の `Upload` 呼び出しで可能なパートアップロードの同時実行数の上限を制御します。これはグローバルなクライアント同時実行数の上限ではありません。`PartSize` と `Concurrency` の設定値を調整して、最適な設定を見つけることができます。例えば、高帯域幅の接続を備えたシステムでは、送信パートサイズを大きくしたり、並列アップロード数を増やしたりできます。

 例えば、アプリケーションで `Uploader` の `Concurrency` を `5` に設定したとします。そのアプリケーションが異なる 2 つの goroutine から `Upload` を呼び出すと、結果は `10` の同時パートアップロード (2 goroutine × 5 `Concurrency`) になります。

**警告**  
 アプリケーションはリソースの枯渇を防ぐために、`Upload` の同時呼び出し数を制限することが求められます。

 次に示しているのは、`Uploader` 作成時にデフォルトのパートサイズを設定する例です。

```
uploader := manager.NewUploader(client, func(u *Uploader) {
    u.PartSize = 10 * 1024 * 1024, // 10 MiB
})
```

 `Uploader` とその設定の詳細については、 AWS SDK for Go API リファレンスの[「アップローダー](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/feature/s3/manager#Uploader)」を参照してください。

#### PutObjectInput 本文フィールド (io.ReadSeeker と io.Reader の比較)
<a name="putobjectinput-body-field-ioreadseeker-vs-ioreader"></a>

 `s3.PutObjectInput` 構造体の `Body` フィールドは `io.Reader` 型です。ただし、ホスト環境でのリソース使用率を最適化するために、このフィールドには、`io.ReadSeeker` と `io.ReaderAt` の両方のインターフェイスを実装した型を指定できます。次の例では、両方のインターフェイスを実装した `ReadSeekerAt` 型を作成しています。

```
type ReadSeekerAt interface {
    io.ReadSeeker
    io.ReaderAt
}
```

 `io.Reader` 型の場合、パートをアップロードする前にリーダーのバイト列をメモリにバッファする必要があります。`PartSize` または `Concurrency` の値を増やすと、`Uploader` に必要なメモリ (RAM) が大幅に増加します。必要なメモリはおよそ *`PartSize`* × *`Concurrency`* です。例えば、`PartSize` に 100 MB、`Concurrency` に 10 を指定した場合、1 GB 以上が必要になります。

 `io.Reader` 型では、バイトを読み込む前にサイズを判別できないため、`Uploader` はアップロードするパートの数を計算できません。その結果、`PartSize` を小さく設定しすぎると、大きなファイルの場合に、`Uploader` は Amazon S3 のアップロード上限である 10,000 パートに達する可能性があります。10,000 パートを超えてアップロードしようとすると、アップロードは停止し、エラーが返されます。

 `ReadSeekerAt` 型を実装した `body` 値の場合、`Uploader` は本文の内容をメモリにバッファせずに Amazon S3 に送信します。`Uploader` は必要なパート数を計算してから、ファイルを Amazon S3 にアップロードします。`PartSize` の現在の値でファイルのアップロードに 10,000 を超えるパートが必要になる場合、`Uploader` はパートサイズの値を増やして、必要なパート数を減らします。

#### アップロード失敗時の処理
<a name="handling-failed-uploads"></a>

 Amazon S3 へのアップロードが失敗した場合、デフォルトでは `Uploader` が Amazon S3 の `AbortMultipartUpload` オペレーションを使用して、アップロードされたパートを削除します。この機能により、失敗したアップロードが Amazon S3 のストレージを無駄に消費しないようにできます。

 `LeavePartsOnError` を true に設定することで、`Uploader` が正常にアップロードされたパートを削除しないようにできます。これは、部分的に完了したアップロードを再開する際に便利です。アップロードされたパートを操作するには、失敗したアップロードの `UploadID` を取得する必要があります。次の例では、`manager.MultiUploadFailure` エラーインターフェイス型を使用して `UploadID` を取得する方法を示しています。

```
result, err := uploader.Upload(context.TODO(), &s3.PutObjectInput{
    Bucket: aws.String("amzn-s3-demo-bucket"),
    Key:    aws.String("my-object-key"),
    Body:   uploadFile,
})
output, err := u.upload(input)
if err != nil {
    var mu manager.MultiUploadFailure
    if errors.As(err, &mu) {
        // Process error and its associated uploadID
        fmt.Println("Error:", mu)
        _ = mu.UploadID() // retrieve the associated UploadID
    } else {
        // Process error generically
        fmt.Println("Error:", err.Error())
    }
    return
}
```

#### アップロードごとの Uploader オプションのオーバーライド
<a name="overriding-uploader-options-per-upload"></a>

 `Upload` を呼び出す際に、1 つ以上の引数を渡すことで、`Uploader` オプションをオーバーライドできます。これらのオーバーライドは同時実行環境でも安全に実行でき、現在進行中のアップロードやその後の `Upload` 呼び出しには影響しません。例えば、特定のアップロードリクエストに対して `PartSize` 設定をオーバーライドするには、次のようにします。

```
params := &s3.PutObjectInput{
    Bucket: aws.String("amzn-s3-demo-bucket"),
    Key:    aws.String("my-key"),
    Body:   myBody,
}
resp, err := uploader.Upload(context.TODO(), params, func(u *manager.Uploader) {
    u.PartSize = 10 * 1024 * 1024, // 10 MiB
})
```

#### 例
<a name="examples"></a>

##### Amazon S3 にフォルダをアップロードする
<a name="upload-a-folder-to-s3"></a>

 次の例では、`path/filepath` パッケージを使用してファイルのリストを再帰的に収集し、指定した Amazon S3 バケットにアップロードしています。Amazon S3 オブジェクトのキーには、ファイルの相対パスがプレフィックスとして付加されます。

```
package main

import (
    "context"
    "log"
    "os"
    "path/filepath"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

var (
    localPath string
    bucket    string
    prefix    string
)

func init() {
    if len(os.Args) != 4 {
        log.Fatalln("Usage:", os.Args[0], "<local path> <bucket> <prefix>")
    }
    localPath = os.Args[1]
    bucket = os.Args[2]
    prefix = os.Args[3]
}

func main() {
    walker := make(fileWalk)
    go func() {
        // Gather the files to upload by walking the path recursively 
        if err := filepath.Walk(localPath, walker.Walk); err != nil {
            log.Fatalln("Walk failed:", err)
        }
        close(walker)
    }()

    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        log.Fatalln("error:", err)
    }
    
    // For each file found walking, upload it to Amazon S3
    uploader := manager.NewUploader(s3.NewFromConfig(cfg))
    for path := range walker {
        rel, err := filepath.Rel(localPath, path)
        if err != nil {
            log.Fatalln("Unable to get relative path:", path, err)
        }
        file, err := os.Open(path)
        if err != nil {
            log.Println("Failed opening file", path, err)
            continue
        }
        defer file.Close()
        result, err := uploader.Upload(context.TODO(), &s3.PutObjectInput{
            Bucket: &bucket,
            Key:    aws.String(filepath.Join(prefix, rel)),
            Body:   file,
        })
        if err != nil {
            log.Fatalln("Failed to upload", path, err)
        }
        log.Println("Uploaded", path, result.Location)
    }
}

type fileWalk chan string

func (f fileWalk) Walk(path string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }
    if !info.IsDir() {
        f <- path
    }
    return nil
}
```

### ダウンロードマネージャー
<a name="download-manager"></a>

 Amazon S3 [Downloader](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/feature/s3/manager#Downloader) マネージャーは、ファイルを小さなパートに分割可能かどうかを判断し、可能な場合は並列でダウンロードします。並列ダウンロードの数とダウンロードされるパートのサイズをカスタマイズできます。

#### 例: ファイルをダウンロードする
<a name="example-download-a-file"></a>

 次の例では、Amazon S3 `Downloader` を使用してファイルをダウンロードしています。`Downloader` の使用は [s3.GetObject](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#Client.GetObject) オペレーションと似ています。

```
import "context"
import "github.com/aws/aws-sdk-go-v2/aws"
import "github.com/aws/aws-sdk-go-v2/config"
import "github.com/aws/aws-sdk-go-v2/service/s3"
import "github.com/aws/aws-sdk-go-v2/feature/s3/manager"

// ...

cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    log.Println("error:", err)
    return
}

client := s3.NewFromConfig(cfg)

downloader := manager.NewDownloader(client)
numBytes, err := downloader.Download(context.TODO(), downloadFile, &s3.GetObjectInput{
    Bucket: aws.String("amzn-s3-demo-bucket"), 
    Key:    aws.String("my-key"),
})
```

 `downloadFile` パラメータは `io.WriterAt` 型です。`WriterAt` インターフェイスを使用して、`Downloader` はファイルの複数のパートを並列で書き込むことができます。

#### 設定オプション
<a name="configuration-options-1"></a>

 `Downloader` インスタンスを作成する際、設定オプションを指定して、オブジェクトのダウンロード方法をカスタマイズできます。
+  `PartSize` – ダウンロードする各パートのバッファサイズをバイト単位で指定します。パートごとの最小サイズは 5 MB です。
+  `Concurrency` – 並行でダウンロードするパートの数を指定します。

 `Concurrency` の値は、1 回の `Download` 呼び出しで可能なパートダウンロードの同時実行数の上限を制御します。これはグローバルなクライアント同時実行数の上限ではありません。`PartSize` と `Concurrency` の設定値を調整して、最適な設定を見つけることができます。例えば、高帯域幅の接続を備えたシステムでは、受信パートサイズを大きくしたり、並列ダウンロード数を増やしたりできます。

 例えば、アプリケーションで `Downloader` の `Concurrency` を `5` に設定したとします。そのアプリケーションが異なる 2 つの goroutine から `Download` を呼び出すと、結果は `10` の同時パートダウンロード (2 goroutine × 5 `Concurrency`) になります。

**警告**  
 アプリケーションはリソースの枯渇を防ぐために、`Download` の同時呼び出し数を制限することが求められます。

 `Downloader` とそのその他の設定オプションの詳細については、 AWS SDK for Go API リファレンスの[「manage.Downloader](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/feature/s3/manager/#Downloader)」を参照してください。

#### ダウンロードごとの Downloader オプションのオーバーライド
<a name="overriding-downloader-options-per-download"></a>

 `Download` を呼び出すときに、1 つ以上の関数型引数を渡すことで、`Downloader` オプションをオーバーライドできます。これらのオーバーライドは同時実行環境でも安全に実行でき、現在進行中のダウンロードやその後の `Download` 呼び出しには影響しません。例えば、特定のアップロードリクエストに対して `PartSize` 設定をオーバーライドするには、次のようにします。

```
params := &s3.GetObjectInput{
    Bucket: aws.String("amzn-s3-demo-bucket"),
    Key:    aws.String("my-key"),
}
resp, err := downloader.Download(context.TODO(), targetWriter, params, func(u *manager.Downloader) {
    u.PartSize = 10 * 1024 * 1024, // 10 MiB
})
```

##### 例
<a name="examples-1"></a>

##### バケット内のすべてのオブジェクトをダウンロードする
<a name="download-all-objects-in-a-bucket"></a>

 次の例では、ページ分割を使用して Amazon S3 バケットからオブジェクトのリストを収集しています。その後、各オブジェクトをローカルファイルにダウンロードしています。

```
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "path/filepath"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

var (
    Bucket         = "amzn-s3-demo-bucket" // Download from this bucket
    Prefix         = "logs/"    // Using this key prefix
    LocalDirectory = "s3logs"   // Into this directory
)

func main() {
    cfg, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        log.Fatalln("error:", err)
    }

    client := s3.NewFromConfig(cfg)
    manager := manager.NewDownloader(client)

    paginator := s3.NewListObjectsV2Paginator(client, &s3.ListObjectsV2Input{
        Bucket: &Bucket,
        Prefix: &Prefix,
    })

    for paginator.HasMorePages() {
        page, err := paginator.NextPage(context.TODO())
        if err != nil {
            log.Fatalln("error:", err)
        }
        for _, obj := range page.Contents {
            if err := downloadToFile(manager, LocalDirectory, Bucket, aws.ToString(obj.Key)); err != nil {
                log.Fatalln("error:", err)
            }
        }
    }
}

func downloadToFile(downloader *manager.Downloader, targetDirectory, bucket, key string) error {
    // Create the directories in the path
    file := filepath.Join(targetDirectory, key)
    if err := os.MkdirAll(filepath.Dir(file), 0775); err != nil {
        return err
    }

    // Set up the local file
    fd, err := os.Create(file)
    if err != nil {
        return err
    }
    defer fd.Close()

    // Download the file using the AWS SDK for Go
    fmt.Printf("Downloading s3://%s/%s to %s...\n", bucket, key, file)
    _, err = downloader.Download(context.TODO(), fd, &s3.GetObjectInput{Bucket: &bucket, Key: &key})

    return err
}
```

### GetBucketRegion
<a name="getbucketregion"></a>

 [GetBucketRegion](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/feature/s3/manager#GetBucketRegion) は、Amazon S3 バケットの AWS リージョンの場所を決定するためのユーティリティ関数です。 `GetBucketRegion` は Amazon S3 クライアントを取得し、それを使用して、クライアントの設定済みリージョンに関連付けられた AWS パーティション内のリクエストされたバケットの場所を決定します。

 例えば、バケット `amzn-s3-demo-bucket` のリージョンを見つけるには、次のようにします。

```
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
    log.Println("error:", err)
    return
}

bucket := "amzn-s3-demo-bucket"
region, err := manager.GetBucketRegion(ctx, s3.NewFromConfig(cfg), bucket)
if err != nil {
    var bnf manager.BucketNotFound
    if errors.As(err, &bnf) {
        log.Printf("unable to find bucket %s's Region\n", bucket)
    } else {
        log.Println("error:", err)
    }
    return
}
fmt.Printf("Bucket %s is in %s region\n", bucket, region)
```

 `GetBucketRegion` がバケットの場所を解決できない場合、例に示すように、この関数は [BucketNotFound](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/feature/s3/manager#BucketNotFound) エラー型を返します。

## シーク不可能なストリーミング入力
<a name="unseekable-streaming-input"></a>

 `PutObject` や `UploadPart` などの API オペレーションでは、Amazon S3 クライアントは、入力パラメータ `Body` の値がデフォルトで [io.Seeker](https://pkg.go.dev/io#Seeker) インターフェイスを実装していることを前提としています。`io.Seeker` インターフェイスは、クライアントがアップロードする値の長さを判断したり、[リクエスト署名](https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html)のためのペイロードハッシュを計算したりするために使用されます。`Body` 入力パラメータ値が `io.Seeker` を実装していない場合、アプリケーションにはエラーが返されます。

```
operation error S3: PutObject, failed to compute payload hash: failed to seek
body to start, request stream is not seekable
```

 この動作は、オペレーションメソッドの [ミドルウェア](middleware.md) を関数型オプションを使用して変更することで制御できます。[WithAPIOptions](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#WithAPIOptions) ヘルパーは、0 個以上のミドルウェアミューテーター用の関数型オプションを返します。クライアントによるペイロードハッシュの計算を無効にし、[署名なしペイロード](https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html)リクエスト署名を使用するには、[v4.SwapComputePayloadSHA256ForUnsignedPayloadMiddleware](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/aws/signer/v4#SwapComputePayloadSHA256ForUnsignedPayloadMiddleware) を追加します。

```
resp, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
    Bucket: &bucketName,
    Key: &objectName,
    Body: bytes.NewBuffer([]byte(`example object!`)),
    ContentLength: 15, // length of body
}, s3.WithAPIOptions(
    v4.SwapComputePayloadSHA256ForUnsignedPayloadMiddleware,
))
```

**警告**  
 Amazon S3 では、オブジェクトをバケットにアップロードするすべてのオペレーションで、ContentLength を指定する必要があります。`Body` 入力パラメータが `io.Seeker` インターフェイスを実装していないため、クライアントはリクエストに必要な `ContentLength` パラメータを計算できません。このパラメータはアプリケーションが指定する必要があります。`ContentLength` パラメータが指定されていない場合、リクエストは失敗します。  
 シーク不可能で長さが不明なアップロードには、SDK の [Amazon S3 アップロードマネージャー](#s3-upload-manager) を使用してください。