最初に
AWS SDK for Go使います。
持ってない人はこちら
Goを使ってのAWS S3からのダウンロード記事をさっぱり見ない。アップロードの記事はちらほら見かけるのに...
やりたいこと
AWSのS3から何かのファイルをひとつダウンロードするよ。
SDKのS3Managerパッケージを使うとダウンロードが簡単に出来るらしい。
コード
長くなった...
main.go
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/defaults"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
)
//ダウンロードするオブジェクトの構造体
type downloader struct {
*s3manager.Downloader
bucket string
file string
dir string
}
func main() {
ACCESSKEY_ID := "AWSのアクセスキーID"
SECLET_ACCESSKEY := "AWSのシークレットアクセスキー"
REGION := "AWSアカウントのリージョン情報"
//AWSの認証情報を設定
defaults.DefaultConfig.Credentials = credentials.NewStaticCredentials(ACCESSKEY_ID, SECLET_ACCESSKEY, "")
defaults.DefaultConfig.Region = ®ION
bucketName := "バケット名"
key := "ファイル名"
localDir := "ダウンロード保存先のローカルパス"
//S3に接続してダウンロード
if err := Download(bucketName, key, localDir); err != nil {
fmt.Printf("ダウンロード失敗!! %s", err)
}
}
func Download(bucketName string, key string, dir string) error {
client := s3.New(nil)
params := &s3.ListObjectsInput{Bucket: &bucketName, Prefix: &key}
//respにはkeyに部分一致したS3の全てのオブジェクトが入る
resp, connectErr := client.ListObjects(params)
if connectErr != nil {
return connectErr
}
//respの中身にダウンロードするファイルがあるのかをチェック
if !exists(key, resp) {
return fmt.Errorf("バケット内にダウンロードするファイルが存在しない")
}
manager := s3manager.NewDownloader(nil)
d := downloader{bucket: bucketName, file: key, dir: dir, Downloader: manager}
if file, err := d.downlowdFile(key); err != nil {
if err := os.Remove(file); err != nil {
fmt.Println(err)
}
return err
}
return nil
}
func exists(downloadFile string, resp *s3.ListObjectsOutput) bool {
for _, content := range resp.Contents {
if *content.Key == downloadFile {
return true
}
}
return false
}
func (d *downloader) downlowdFile(key string) (string, error) {
buffKeys := strings.Split(key, "/")
fileName := buffKeys[len(buffKeys)-1]
file := filepath.Join(d.dir, fileName)
//ダウンロード保存先に、ダウンロード用のファイルを作成
fs, err := os.Create(file)
if err != nil {
return file, err
}
defer fs.Close()
fmt.Printf("ダウンロード中.. s3://%s/%s to %s...\n", d.bucket, key, file)
params := &s3.GetObjectInput{Bucket: &d.bucket, Key: &key}
//実際にダウンロードが行われるのはこのDownload関数
if _, err := d.Download(fs, params); err != nil {
return file, err
}
fmt.Printf("ダウンロード完了! %s", file)
return file, nil
}
AWSの認証情報を設定している部分は、SDKのdefaultパッケージとcredentials
パッケージを使ってハードコーディングしてます。
でも、あまり推奨されない方法なので環境変数を設定するか、専用の認証ファイルを作成するのが普通みたいです。(ここに書いてあった)
実際にダウンロードを行うd.Downloadは、SDKの*s3manager.Downloaderの関数です。
ソースコードを見た感じだと、先にローカルの保存先にファイルを作成してから、そのファイルポインタを渡して内容を書き込んでるように見えます。違ったらごめんなさい。
終わり
コードに無駄な部分があるかもしれないけど、とりあえず動いたから良し。