0
0

More than 1 year has passed since last update.

Go で Azure Storage Blobを扱うときの覚え書き

Posted at

Go で Azure Storage Blobを扱うときの覚え書き

azblobに関する、備忘録代わりの記事です。(古い記事やパッケージなどが検索に紛れてきてしまうので)

SDKのリポジトリは以下にあります。執筆時点で v1.0.0 が最新です(ちょうど執筆前にリリースされたようです) 以前のバージョン(v0.5 とか v0.6)を使っている人はアップデートするとよいでしょう。

パッケージは以下にあります。

azblobと検索すると、古いバージョンが先にヒットしてしまう場合がありあますが、理由がなければ使わないようにしましょう。

一般的な使い方

他のSDKでよくある使い方、例えば

  1. 接続文字列でクライアントを作る
  2. コンテナオブジェクトを作り、コンテナを作成する(CreateIfNotExistとか)
  3. BLOBオブジェクトを作り、アップロード・ダウンロードする

みたいなシナリオをGoで書いてみます。

初期設定

初期化してSDKを取得しておきます。

go mod init main
go get github.com/Azure/azure-sdk-for-go/sdk/storage/azblob

接続文字列外のクレデンシャルを使う場合は、azidentity も必要です。

go get github.com/Azure/azure-sdk-for-go/sdk/azidentity

接続からコンテナの作成まで

接続文字列からクライアントを作成して、コンテナを作る簡単なコード例です。AZURE_STORAGE_CONNECTION_STRING に接続文字列を設定しておきます。
特に難しいところないのですが、コンテナが既に存在するとエラーが発生するので、自分でハンドルするしか無さそうです。どうやってハンドルするのか分からなかったので、ソースをつらつら参照していたら、bloberror.HasCode という関数があったので使ってみましたが、一応これで判断が可能ですが、正しい方法か分かりません。

パッケージの説明には、

| CreateContainer is a lifecycle method to creates a new container under the specified account. If the container with the same name already exists, a ResourceExistsError will be raised. This method returns a client with which to interact with the newly created container.

と、ResourceExistsError なるものがRaiseされると書かれていましたが、ソースをググってもそれに該当しそうなコードは見つかりませんでした。なんとなく他の言語のSDKの説明なのではないかという感じです(Pythonぽい)。

	ctx := context.Background()
	connectionString, ok := os.LookupEnv("AZURE_STORAGE_CONNECTION_STRING")
	if !ok {
		log.Fatal("'AZURE_STORAGE_CONNECTION_STRING' not found")
	}

	// 接続文字列でクライアントを作成する
	serviceClient, err := azblob.NewClientFromConnectionString(connectionString, nil)
	if err != nil {
		panic(err)
	}

    // コンテナの作成
	r, err := serviceClient.CreateContainer(ctx, "test-container", &azblob.CreateContainerOptions{})

	if err != nil {
		if bloberror.HasCode(err, bloberror.ContainerAlreadyExists) {
			// コンテナが既に存在する
			fmt.Printf("container already exists")
		} else {
			panic(err)
		}
	}
	fmt.Printf("%v\n", r)

ファイルのアップロード

他のSDKだとコンテナを作成すると、コンテナ用のクライアントオブジェクトが取得できて、それに対してBlobClientを作成してアップロードみたいな感じですが、GoではすべてserviceClient で処理します

アップロードする関数はいくつかありますが、以下はFileからの例です。特にオプションを指定しないと、Blobは常に上書きされます。

	f, err := os.Open("./sample.txt")
	if err != nil {
		panic(err)
	}

	r, err := serviceClient.UploadFile(ctx, "test-container", "sample.txt", f, &azblob.UploadFileOptions{})
	if err != nil {
		panic(err)
	}
    fmt.Printf("%v\n", r2)

とはいえ、上書きされたくないときもあると思いますが、他のSDKのように overwrite=false 的な物はなくて、ETAGで制御しないとならないようです。If-None-Match*を指定すると、リソースが存在しない限り実行される振る舞いをするので、それを利用します。

	o := &azblob.UploadFileOptions{
		AccessConditions: &blob.AccessConditions{
			ModifiedAccessConditions: &blob.ModifiedAccessConditions{IfNoneMatch: to.Ptr(azcore.ETagAny)},
		},
	}
	r, err := serviceClient.UploadFile(ctx, "test-container", "sample.txt", f, o)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%v\n", r2)

その値の細かい話は以下に書かれています。

BLOB サービス操作の条件付きヘッダーの指定 (REST API) - Azure Storage | Microsoft Learn

ダウンロード

ダウンロードにもいくつか関数があり、File/Stream/Bufferなどがあります。以下は、Streamの例です。レスポンスボディを文字に変換して出力しています。

	dr, err := serviceClient.DownloadStream(ctx, "test-container", "sample.txt", nil)
	if err != nil {
		panic(err)
	}

	data, err := io.ReadAll(dr.Body)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(data))

まとめ

さくっと接続、アップロード、ダウンロードを試してみましたが、これがGoらしいのかはちょっとよく分かりませんが、多分そうなのでしょう。あと、他のSDKに慣れているとちょっととっつきにくいかもしれません。

一応ガイドライン的な物もあるので、紹介しておきます(以前ドラフトですけど)

Go Azure SDK Design Guidelines | Azure SDKs

以上(つづく)

0
0
0

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
0
0