LoginSignup
10
13

More than 5 years have passed since last update.

GoでAWSのS3からファイルをダウンロードする

Last updated at Posted at 2015-11-11

最初に

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 = &REGION

    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の関数です。
ソースコードを見た感じだと、先にローカルの保存先にファイルを作成してから、そのファイルポインタを渡して内容を書き込んでるように見えます。違ったらごめんなさい。

終わり

コードに無駄な部分があるかもしれないけど、とりあえず動いたから良し。

10
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
13