【Kotlin】Kotlin ~ 基本編 / ファイルの扱い ~

■ はじめに

 日本の祝日を判定する処理を考えていて、
調べてみると、結構大変そうだなっと。
(例えば、「山の日」は、2020年08月10日で、2021年08月10日。
情勢などでも変わって、単純にプログラムで実装できない部分がある)
更に、過去や未来のメンテナンスまで考えると、更に複雑になる。
⇒ 理想は、Webサービスで管理して、常に取得とか?

で、調査している最中に、内閣府のサイト(※)で、
「昭和30年(1955年)から令和3年(2021年)国民の祝日(csv形式:19KB)」
があった。

まずは、手始めとして、Kotlinでこのファイルを開く方法を考える。

内閣府のサイト

https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html
syukujitsu.csvSJIS

国民の祝日・休日月日,国民の祝日・休日名称
1955/1/1,元日
1955/1/15,成人の日
・・・
2021/10/11,スポーツの日
2021/11/3,文化の日
2021/11/23,勤労感謝の日

目次

■ CSV
■ try-with-resources
■ サンプル

CSV

今回は、「syukujitsu.csv」を見る限り、
トリッキーな形式はなさそうだったので
String クラスの split メソッドを使用する

https://maku77.github.io/kotlin/numstr/split.html
補足:CSVライブラリ

複雑なCSVであれば...

 以下のサイトのように
「Apache commons-csv」や「OpenCSV」などの
CSVライブラリを使う方がいい

https://qiita.com/motch0214/items/aecda8e636b857510a90
http://wild-data-chase.com/index.php/2019/06/15/post-860/

■ try-with-resources

https://qiita.com/jutaroi01/items/ee88a402028ef9e338ed

より抜粋、『kotlinにはtry-with-resourcesそのものはない』
代わりに use が使えるらしい。

■ サンプル

準備

* assertsフォルダがない場合は、[New]-[Folder]-[asserts folder] を選択

https://codechacha.com/ja/how-to-use-assets-in-android/
CsvReader.kt

import android.content.res.AssetManager
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.nio.charset.Charset

class CsvReader(assertManager: AssetManager, csvFilePath: String) {
    private val assertManager = assertManager
    private val csvFilePath = csvFilePath

    fun readCsv(
        skipLine: Int = 0,
        encoding: String = "UTF-8",
        delimiter: String = ","
    ): List<List<String>> {
        return this.readCsv(
            this.assertManager.open(this.csvFilePath),
            skipLine,
            encoding,
            delimiter
        )
    }

    private fun readCsv(
        inputCsv: InputStream,
        skipLine: Int,
        encoding: String,
        delimiter: String
    ): List<List<String>> {
        val csvContents = mutableListOf<List<String>>()
        try {
            BufferedReader(
                InputStreamReader(
                    inputCsv, Charset.forName(encoding)
                )
            ).use { fileReader ->
                var lineNumber: Int = 1
                fileReader.forEachLine { line ->
                    if (line.isNotBlank()) {
                        if (lineNumber > skipLine) {
                            val contents =
                                line.split(delimiter).map { value ->
                                    value.trim()
                                }
                            csvContents.add(contents)
                        }
                    }
                    lineNumber++;
                }
            }
        } catch (ex: IOException) {
            ex.printStackTrace()
        }
        return csvContents
    }
}

Main.kt

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import xxxx.xxx.xxxxx.CsvReader
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button.setOnClickListener {
            val csvReader = CsvReader(this.assets, "systems/syukujitsu.csv")
            // 1行目はヘッダーなので飛ばす。SJIS形式を指定。
            val csvContents = csvReader.readCsv(1, "SJIS")
            for (contents in csvContents) {
                for (content in contents) {
                    Log.i("[Result]", "content = $content")
                }
            }
        }
    }
}

出力結果

I/[Result]: content = 1955/1/1
    content = 元日
    content = 1955/1/15
    content = 成人の日
    content = 1955/3/21
・・・
    content = 2021/11/3
    content = 文化の日
    content = 2021/11/23
    content = 勤労感謝の日

参考文献

https://www.programming-shimomura.com/2017/06/23/%E3%80%90android%E3%80%91csv%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%AE%E5%AE%9F%E8%A3%85%EF%BC%88%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E4%BB%98%E3%81%8D%EF%BC%89/
エンコード
https://qiita.com/ryuumikoto/items/2c884b3dfbb228ac1065
https://qiita.com/KenjiOtsuka/items/5a9a3bba715b151bc061

関連記事

Kotlin ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2018/09/13/001546
Kotlin ~ 基本編 / 配列・コレクション ~
https://dk521123.hatenablog.com/entry/2020/07/07/000000
Kotlin ~ 基本編 / クラス ~
https://dk521123.hatenablog.com/entry/2020/07/23/000000
Kotlin ~ 基本編 / 日付・時間 ~
https://dk521123.hatenablog.com/entry/2020/07/27/000000