Android-Java で画像ファイルを Azure Blob Storageへアップロードする

# 自己紹介

大同大学2年生の久米　史也です。
Xamarin とかいじってます。

# Azure Blob Storage とは

> Azure Blob Storage はエクサバイト単位の容量と極めて高いスケーラビリティを備えており、必要なデータ アクセス頻度に応じてホット層またはクール層に、数百個から数十億個のオブジェクトを簡単かつコスト効率よく保管することができます。画像、ビデオ、音声、ドキュメントなど、あらゆる種類の非構造化データを保存できます。

[https://azure.microsoft.com/ja-jp/services/storage/blobs/](https://azure.microsoft.com/ja-jp/services/storage/blobs/) より引用

正確ですが、読みにくい文章なので、少しかみ砕いて解説します。
簡単に言うと、画像とか、テキストとか、ビデオとかのあらゆるファイルを保存できるストレージです。

SNS 等で、ユーザーの投稿したデータを保存するのに使うと、イメージしていただけるとわかりやすいかと。

ファイルの保存やクラウドからの転送にかかる料金は、

- ファイルの保存：1TB までが、￥2.45/GB だったり、
- クラウドからの転送：100,000 回あたり、 ￥0.37

といった感じです。お安めかなと思います。

参考資料: [Azure Storage 料金](https://azure.microsoft.com/ja-jp/pricing/details/storage/blobs-general/)

# 今回やっていくこと

Android から 画像を Azure Blob Storage へアップロードしていきます。

# 準備

- サブスクリプションが有効になっている Microsoft Azure アカウント
- Android Studio (自分は、2.3 を使いました)

# やったこと

## 1. Android のプロジェクトを作成

### Empty Activity のテンプレートを選べば大丈夫かなと思います。

![studio64_2017-03-31_23-08-29[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/ef01903a-2adf-e9ca-a6f6-7e8a21f9648f.png)

## 2. ボタンを一つ配置する

// 基本的なところなので、コードは省略

id は **button** にしておきます。

## 3. Azure 側の準備をする

### Azure Portal へアクセス

![chrome_2017-03-31_23-11-25[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/2f38de9e-0edc-1753-0273-7ff8bb759d05.png)

### Blob Storage を作成

右上の **+** ボタンをクリックすると出てくる検索ボックスに **Blob** と入力すると Azure Blob Storage がサジェストされるのでそれをクリックします。

![chrome_2017-03-31_23-12-23[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/1f555f83-2453-72ca-1cb9-37063d1803a1.png)

### Azure Blob Storage の設定を続ける

名前は、 Azure 内全ユーザーでユニークな 名前を付けてあげてください。
リソースグループは、個々のユーザーごとにユニークな名前をつけてください。
サブスクリプションについては、 Imagine でもらえるサブスクリプションでは作成することができないので、 [MSP の主催するイベント](https://mspjp.connpass.com/) 等に参加することでもらえる **Azure Pass** 等を利用してください

最後に、**ダッシュボードにピン止めをする** をクリック、完了をクリックで設定は終了です。

![chrome_2017-03-31_23-16-07[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/20642947-0058-8874-98a0-4f72c4f7e2ca.png)

### Azure Blob Storage の作成が完了

以下のような画面が開くかと思います。

![chrome_2017-03-31_23-21-54[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/1fccb31f-1cb9-cb49-d6da-e98e2f7266f0.png)

サービスカテゴリの **Blob** という部分を開いてみましょう

![chrome_2017-03-31_23-35-49[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/43c47a8e-983d-59ac-b05d-21d5a1c65590.png)

![chrome_2017-04-01_00-05-23[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/e9552e13-bbf5-e1bf-3ffd-c548d610fab4.png)


まだ、コンテナーが作成されていないというメッセージが出たかと思います。

コンテナー... どのようなものでしょうか？

ここで、 Azure Blob Storage の仕組みについて見ていきましょう。

![blob1[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/7cd72ff9-c4a5-73b5-b2d9-32d2f46f2ab2.png)

[.NET を使用して Azure Blob Storage を使用する](https://docs.microsoft.com/ja-jp/azure/storage/storage-dotnet-how-to-use-blobs) より引用

ぱっと見で分かりにくいかもしれません、普段使い慣れているコンピュータ用語に置き換えて考えてみてはどうでしょうか？

アカウント ＝　USB メモリ
コンテナー ＝　USB メモリ に入っているフォルダ
BLOB ＝　フォルダの中に置かれている画像コレクションや動画コレクション

わかるような気がしますよね？

### Azure Blob のコンテナーを作成

左上のボタンからコンテナーを作成していきます。

![chrome_2017-04-01_00-38-25[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/47b02722-3d93-1d7e-1d00-65e4b8554352.png)

Azure Blob Storage のコンテナーの名前を付けるときの注意点ですが、すべて小文字にしなければいけません

また、アクセスの種類は Blob にしてください

これで、 Azure の準備は完了しました。

## 4. Android 側の Azure Blob Storage と接続するためのロジックの作成

Android の **MainActivity.java** を開いてください。
そして、以下のコードを入力してください

```java

// import は省略

public class MainActivity extends AppCompatActivity {

    public Button Button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button = (Button) findViewById(R.id.button);
        Button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // UIスレッドでネットワークを使った重い処理を実行させるとつらみが発生するため、別スレッドで実行
                AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        // Azure Blob Storage と接続するための文字列、チョー重要。 Root アカウントのパスワードぐらい重要です。
                        String storageConnectionString = "Connection String";
                        // DCIM へのパスを取得
                        File dir = new File(Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DCIM);
                        // DCIM 上の画像ファイルへのパスを設定
                        File file = new File(dir.getAbsolutePath() + "/image.jpeg");
                        // 正しい画像へのパスが取れているか確認のためにログ出力
                        Log.d("画像を表示させるやつ", file.getPath());
                        try {
                            // Azure Storage Account との接続を開始
                            CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);

                            // Azure Storage Account の Blob との接続するためのクライアントを取得
                            CloudBlobClient blobClient = storageAccount.createCloudBlobClient();

                            // Blob のコンテナーを取得している、コンテナーの指定は文字列で行う
                            CloudBlobContainer container = blobClient.getContainerReference("mspjp");

                            // getBlockBlobReference の引数で渡している文字列が、 Blob 内に保存されるファイル名になる。
                            // すでに同じ名前のファイルが存在するときは、上書きされる
                            CloudBlockBlob blob = container.getBlockBlobReference("myimage.jpg");
                            // ファイルが存在しなかったら 関数を終了させる
                            if (!file.exists()) return null;
                            // Azure Blob Storage へアップロード
                            blob.upload(new java.io.FileInputStream(file), filelength());
                        } catch (Exception e) {
                            // エラーが起きたら解析用にスタックトレースを吐かせる
                            e.printStackTrace();
                        }
                        return null;
                    }
                };

                try {
                    // 別スレッドで実行させる
                    task.execute();
                } catch (Exception e) {
                    Handler handler = new Handler();
                    handler.post(new Runnable() {
                        // エラーが発生したらトーストでエラーメッセージを表示させたいが、
                        // UI スレッドでなければ、トーストを表示させれないため、 UI スレッドで実行している
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "Faild: Upload blob storage", Toast.LENGTH_LONG).show();
                        }
                    });
                }
            }
        });

    }
}
```

## 5. アップロードするための画像の配置

Android を PC とつなぎ、 Android の外部ストレージを開いて、 そのなかにある　 **DCIM** というフォルダの中に、 **image.jpeg** という画像ファイルを置いてください

## 6. storageConnectionString の設定

storageConnectionString は各ユーザー（ Storage Account）ごとに違う ので今から取得していきましょう。

まずは、先ほど作成した Azure Blob Storage の画面を開いてください

アクセスキーと書かれた部分をクリックしてください

![chrome_2017-04-01_01-03-35[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/0b728d4f-4852-cd5d-3832-26f21b95333d.png)

**key1** の接続文字列をコピーして **storageConnectionString** に代入するようにコードを書き換えてください

![chrome_2017-04-01_01-04-31[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/068a96a5-c0df-7d3a-4822-fefeb91f6e9b.png)

## 実行

以上でコーディングは終了したので、実行してみてください。

実行後、 Azure Blob Storage の コンテナーのところを開くと画像がアップロードされているのがわかるかと思います。

![chrome_2017-04-01_01-08-23[1].png](https://qiita-image-store.s3.amazonaws.com/0/143354/830b12df-1d0b-d290-8d59-d69764735062.png)


# 感想

- Java 楽しい
- Azure はドキュメントがそろっているので、わからないことがあっても解決しやすいと感じました。

# 参考資料

- [Github - Azure/azure-storage-android](https://github.com/Azure/azure-storage-android)
- [Java から BLOB ストレージを使用する方法](https://docs.microsoft.com/ja-jp/azure/storage/storage-java-how-to-use-blob-storage#a-nameset-up-an-azure-storage-connection-stringaazure-storage-接続文字列の設定)
- [Azure Storage の接続文字列を構成する](https://docs.microsoft.com/ja-jp/azure/storage/storage-configure-connection-string)
- [Android の DCIM 上にある画像ファイルを ImageView に表示する](http://kuxumarin.hatenablog.com/entry/2017/03/31/%23_Android_%E3%81%AE_DCIM_%E4%B8%8A%E3%81%AB%E3%81%82%E3%82%8B%E7%94%BB%E5%83%8F%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92_ImageView_%E3%81%AB%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B)