xlsファイル読み込み(Kotlin, AndroidStudio)

# はじめに
AndroidStudioでのxlsファイル読み込み方法について書いていきたいと思います。

今回は以下二通りの場面に分けて実装していきます。

* Assetsフォルダから読み込む
* ファイルアプリからxlsファイルを選び読み込む

> ここでxlsx形式ではなくxls形式を扱っている理由は、xlsx形式のファイルを操作するためには最低でもAPIレベルが26も必要なためです。
ここでの記事は最低APIレベルが26未満の場合を前提として書いています。
最低APIレベル26以上にしている方は以下のサイトを参考にしてください。
[kotlinでExcelからデータを読み込む](https://qiita.com/ato1234/items/54794c7b1e0a04a33463)

# 1. Assetsフォルダから読み込む

## 1.1 準備
### 1.1.1 Assetsフォルダ作成
まずAssetsファルダの作成からやっていきます。

プロジェクトツールウィンドウで「app」 を右クリックしメニューから[New] -> [Folder] -> [Assets Folder] を実行。
フォルダの追加先を選択する画面となりますが、ここでは何も変更しないで「Finish」をクリック。

すると、プロジェクト内に「app/src/main/assets」が作成されます。

### 1.1.2 Excelでxlsファイルを作成
Excelで新しくファイルを作り以下の画像のように値をセットしていきます。
![2021-03-01 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1080547/9fb4af7b-d55b-b4ef-aca2-90488ed3c011.png)

セットできたら名前を付けて保存していきます。
名前は「lessons」
ファイルの種類は「.xls」

![2021-03-01 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1080547/1529b5d1-cb7f-fbbb-a9a0-4fe12800df03.png)

作成出来たらファイルをコピーしassetsフォルダに貼り付けてください。
ダイアログが表示されますがそのまま進めて大丈夫です。



## 1.2コーディング

### 1.2.1 build.gradle(Module)
Excelファイルを操作するためのやつを準備

```build.gradle
dependencies {
   implementation 'org.apache.poi:poi-ooxml:4.1.0'
}
```

### 1.2.2 MainActivity.kt

今回はxlsファイルの中身を用意しておいた変数に代入していき
最後TextViewに表示させるようにします。
``` overruide fun onCreate() {} ``` の中身に以下を追記

```kotlin:MainActivity.kt
        // 結果を表示するための変数を初期化
        var result = ""
        // assetsフォルダからファイルを取り出す
        var file = resources.assets.open("lessons.xls")
        val wb = WorkbookFactory.create(file)
        // 指定したsheetを取り出す
        val sheet = wb.getSheet("lessons_sheet")
        // sheetの最終行まで繰り返す
        // sheet.lastRowNum: 一番下にある要素の行番号
        for (i in 0..sheet.lastRowNum) {
            // それぞれのセル要素を取り出す
            // getRow() : 行, getCell() : 列
            // stringCellValue: セルにある文字列の要素を取得
            var rightCell = sheet.getRow(i).getCell(0).stringCellValue
            var leftCell = sheet.getRow(i).getCell(1).stringCellValue
            result += "$rightCell :$leftCell \n"
        }
        // 結果を用意しておいたTextViewで表示
        binding.textview.text = result

```

* セルから文字列を取得したいときは上記のやり方でいいのですが、数値で取り出したい場合は``` numericCellValue ```を使ってください。

### 1.2.3 実行結果
以上でxlsファイルから値を取り出せることができるようになりました。
今回の場合ですと変数resultの結果は以下のようになります。
![2021-03-01 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1080547/96f52f17-69f4-30d6-7311-73bb1de5b41a.png)


# 2. ファイルアプリからxlsファイルを選び読み込む
つづいて、ユーザーがファイルアプリからxlsファイルを指定し、そのファイルから要素を抽出するプログラムを書いていきたいと思います。

ちなみに、ここでいうファイルアプリは以下の画像でいう「Files」というアプリのことです。
どのスマホでも同じようなアプリがあると思うので事前にインストールしておく心配はいりません。
![2021-03-01 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1080547/b7fa88e2-2248-1c38-54a5-9854202fe00e.png)

## 2.1 準備

ファイルアプリを立ち上げるためのButtonと結果を表示するためのTextviewを
activity_main.xmlに追加します。
配置と値の設定には特に変わった設定はないためご自由に

あとは「Assetsフォルダから読み込む」とそほど変わりません。
ですので、以前の項を参考に「1.1.2 Excelでxlsファイルを作成」「1.2.1 build.gradle(Module)」を事前に作成しておいてください。

> 作成したxlsファイルをファイルアプリで選択できるようにするために、ドラックアンドドロップでAVD側にダウンロードさせてください。

## 2.2 コーディング(MainActivity.kt)

* ファイルアプリを立ち上げる処理を書いていきます。

```kotlin:MainActivity.kt

    // 確認用の変数(値は何でもいい)
    val REQUEST_XLS = 1

    override fun onCreate...

        binding.button.setOnClickListener {
            // 暗黙インテント
            var intent = Intent(Intent.ACTION_GET_CONTENT);
            // 取り出すファイルの形式を指定(今回はxls)
            intent.type = "application/vnd.ms-excel"
            // アプリを立ち上げる
            // REQUEST_XLS: 確認用の変数。
            startActivityForResult(intent, REQUEST_XLS)

        }
```
> ``` intent.type ```ですが取り出したいファイル形式によって変更する必要があります。そのための一覧表を貼っておくので調べたい方は参照してください。
[よくある MIME タイプ](https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)

* 次はファイル選択後の処理です。

```kotlin:MainActivity.kt
    // 選択し終わったら必ず実行されるメソッド
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        // 先ほどの処理から戻ってきたかと処理が正常に終わったかどうかを確認
        if(requestCode == REQUEST_XLS && resultCode == RESULT_OK) {

            // 結果を格納するための変数を用意
            var result = ""
            // 選択したファイルからUriを取得
            val fileUri = data?.data
            // fileUri as Uri: Uri?からUriにキャストさせておく必要がある
            val inputStream = context?.contentResolver?.openInputStream(fileUri as Uri)
            val wb = WorkbookFactory.create(inputStream)
            val sheet = wb.getSheet("lessons_sheet")
            // 以下は以前の項と同じ
            for (i in 0..sheet.lastRowNum) {
               var rightCell = sheet.getRow(i).getCell(0).stringCellValue
               var leftCell = sheet.getRow(i).getCell(1).stringCellValue
               result += "$rightCell :$leftCell \n"
            }
        }
    }
```

## 2.3 動作確認
例として自分の場合の動作をとせておきます。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1080547/596f8f4a-b877-80f9-41be-322cd77609f3.gif)


## 参考文献

[Basic Read and Write to Excel](https://www.youtube.com/watch?v=jRb2rrUnYKw)
[kotlinでExcelからデータを読み込む](https://qiita.com/ato1234/items/54794c7b1e0a04a33463)
[ギャラリーからの画像読み込みでエラーが出るときの修正方法](http://workpiles.com/2014/07/android-gallary-intent/)
[Androidでギャラリーから画像の形式を絞ったうえで複数選択して取り込む方法](https://qiita.com/miyodevelop/items/26d2d77b4c83b9c69dc1)
[Android 画像ファイルを扱う際のFileとUriまとめ](https://qiita.com/wakamesoba98/items/98b79bdfde19612d12b0)