概要
-
まだRC版だけど、AWS SDK for Go v2を使ったS3のオブジェクトアップロードとダウンロードを使ってみた。
https://github.com/aws/aws-sdk-go-v2 -
goを普段触らなけど練習で書いてみた。
前提条件
Goのバージョンがv1.15であること
$ go version
go version go1.15 linux/amd64
準備
go mod init awssdkapp
go get -u github.com/aws/aws-sdk-go-v2
go get -u github.com/aws/aws-sdk-go-v2/config
go get -u github.com/aws/aws-sdk-go-v2/feature/s3/manager
go get -u github.com/aws/aws-sdk-go-v2/service/s3
touch main.go
mkdir myclient
touch myclient/myclient.go
S3に接続するクライアントのコード
シンプルにオブジェクトをアップロードしたり、ダウンロードする。
myclient/myclient.go
package myclient
import (
"context"
"io"
"log"
"os"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
type MyS3Client struct {
downloader *manager.Downloader
uploader *manager.Uploader
client *s3.Client
}
func NewMyS3Client(cfg aws.Config) *MyS3Client {
client := s3.NewFromConfig(cfg)
downloader := manager.NewDownloader(client)
uploader := manager.NewUploader(client)
return &MyS3Client{
downloader: downloader,
uploader: uploader,
client: client,
}
}
// オブジェクトをダウンロードするメソッド
func (c *MyS3Client) UploadSingleObject(bucket, key string, reader io.Reader) {
_, err := c.uploader.Upload(context.Background(), &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: reader,
})
if err != nil {
log.Fatal(err)
}
log.Println("upload successed")
}
// オブジェクトをダウンロードするメソッド
func (c *MyS3Client) DownloadSingleObject(bucket, key, filename string) {
file, _ := os.Create(filename)
defer file.Close()
_, err := c.downloader.Download(context.Background(), file, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
if err != nil {
log.Fatal(err)
}
log.Println("download successed")
}
main.go
package main
import (
"context"
"flag"
"log"
"strings"
"awsdkapp/myclient"
"github.com/aws/aws-sdk-go-v2/config"
)
func main() {
bucket := flag.String("bucket", "", "specify bucket name")
key := flag.String("key", "", "specify key name ")
flag.Parse()
if *bucket == "" || *key == "" {
log.Fatal("error invalid arugments")
}
// コンフィグの作成
cfg, err := config.LoadDefaultConfig(context.Background())
if err != nil {
log.Fatal(err)
}
client := myclient.NewMyS3Client(cfg)
// コンテンツをアップロードする
client.UploadSingleObject(*bucket, *key, strings.NewReader("hello, aws sdk"))
// ファイルとしてダウンロードする
client.DownloadSingleObject(*bucket, *key, "hello.txt")
}
実行してみると、アップロード/ダウンロードできるはず。
$ go run main.go -bucket the-chocomintkusoyaro-demo -key hoge
2020/12/30 23:05:32 upload successed
2020/12/30 23:05:32 download successed
$ ls hello.txt
hello.txt
$ cat hello.txt
hello, aws sdk
複数のオブジェクトをダウンロードする場合
NewListObjectsV2Paginator
でページネータを生成してページ単位でオブジェクト群を取得して、オブジェクト一つ一つをダウンロード書き込みする。
myclient/myclient.go
...
// 複数のオブジェクトをダウンロードする
func (c *MyS3Client) DownloadMultipleObjects(bucket, prefix, localDir string) {
// ページネーターを作成する
paginator := s3.NewListObjectsV2Paginator(c.client, &s3.ListObjectsV2Input{
Bucket: aws.String(bucket),
Prefix: aws.String(prefix),
})
for paginator.HasMorePages() {
page, err := paginator.NextPage(context.Background())
if err != nil {
log.Fatal(err)
}
for _, obj := range page.Contents {
if err != nil {
log.Fatal(err)
}
filepath := filepath.Join(localDir, *obj.Key)
c.DownloadSingleObject(bucket, *obj.Key, filepath)
}
}
log.Println("all file downloaded")
}
main.go
package main
import (
"context"
"flag"
"log"
"awsdkapp/myclient"
"github.com/aws/aws-sdk-go-v2/config"
)
func main() {
bucket := flag.String("bucket", "", "specify bucket name")
prefix := flag.String("prefix", "", "specify prefix name")
localDir := flag.String("localDir", "", "specify local dir ")
flag.Parse()
if *bucket == "" || *localDir == "" {
log.Fatal("error invalid arugments")
}
// コンフィグの作成
cfg, err := config.LoadDefaultConfig(context.Background())
if err != nil {
log.Fatal(err)
}
client := myclient.NewMyS3Client(cfg)
// オブジェクトをダウンロードする
client.DownloadMultipleObjects(*bucket, *prefix, *localDir)
}
複数のオブジェクトをアップロードする
ドキュメントのExampleを真似てみた。
myclient/myclient.go
...
// 複数のオブジェクトをまとめてアップロードする
func (c *MyS3Client) UploadMultipleObjects(bucket, prefix, localDir string) {
fileWalker := make(chan string)
// チャネルにローカルファイルパスを送信する
go func() {
err := filepath.Walk(localDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
// ファイルパスをチャネルに送る
fileWalker <- path
}
return nil
})
if err != nil {
log.Fatal(err)
}
// チャネルのクローズをお知らせるする
close(fileWalker)
}()
// ファイルパスをチャネルから受信する
for path := range fileWalker {
rel, err := filepath.Rel(localDir, path)
if err != nil {
log.Println("unable to get relative path", path, err)
continue
}
file, err := os.Open(path)
if err != nil {
log.Println("failed open file", path, err)
continue
}
defer file.Close()
key := filepath.Join(prefix, rel)
// オブジェクトをダウンロードする
c.UploadSingleObject(bucket, key, file)
}
}
main.go
package main
import (
"context"
"flag"
"log"
"awsdkapp/myclient"
"github.com/aws/aws-sdk-go-v2/config"
)
func main() {
bucket := flag.String("bucket", "", "specify bucket name")
prefix := flag.String("prefix", "", "specify prefix name")
localDir := flag.String("localDir", "", "specify local dir ")
flag.Parse()
if *bucket == "" || *localDir == "" {
log.Fatal("error invalid arugments")
}
// コンフィグの作成
cfg, err := config.LoadDefaultConfig(context.Background())
if err != nil {
log.Fatal(err)
}
client := myclient.NewMyS3Client(cfg)
// オブジェクトをまとめてアップロードする
client.UploadMultipleObjects(*bucket, *prefix, *localDir)
}