2019年3月17日日曜日

JacksonでCSVの読み込み

ヘッダなしCSVファイルの読み込み

CsvSchemaでカラムを定義してBeanとマッピングする。
fun main(args: Array) {
    val csvSchema = CsvSchema.builder()
            .addColumn("id")
            .addColumn("name")
            .build()
    val csvMapper = CsvMapper()
    csvMapper.registerModule(KotlinModule())

    val csvFile = csvMapper.readerFor(CsvFile::class.java)
            .with(csvSchema)
            .readValues("""
                1,test
                2,test2
                3,test3
            """.trimIndent())
    
    csvFile.forEach {
        println("it = ${it}")
    }
    
}

data class CsvFile(
        val id:Long,
        val name:String
)

ヘッダありCSVファイルの読み込み

Schemaに対して、useHeaderを設定するとヘッダありファイルを読み込める。
ヘッダの内容をもとにプロパティとのマッピングが行われるので、ヘッダなしのときのようなSchemaでのカラム定義が必要なくなる。
fun main(args: Array) {
    val csvSchema = CsvSchema.builder()
            .setUseHeader(true)
            .build()
    val csvMapper = CsvMapper()
    csvMapper.registerModule(KotlinModule())

    val csvFile = csvMapper.readerFor(CsvFile::class.java)
            .with(csvSchema)
            .readValues("""
                id,name
                1,test
                2,test2
                3,test3
            """.trimIndent())
    
    csvFile.forEach {
        println("it = ${it}")
    }
    
}

data class CsvFile(
        val id:Long,
        val name:String
)

ヘッダ名とプロパティ名が一致しない場合の読み込み

ヘッダなしのファイルと読み込む場合と同じように、カラム定義が必要となる。
カラム定義を行わず、対象のプロパティに対して@JsonProperty("なまえ")とすることでもマッピングができる。
fun main(args: Array) {
    val csvSchema = CsvSchema.builder()
            .addColumn("id")
            .addColumn("name")
            .setUseHeader(true)
            .build()
    val csvMapper = CsvMapper()
    csvMapper.registerModule(KotlinModule())

    val csvFile = csvMapper.readerFor(CsvFile::class.java)
            .with(csvSchema)
            .readValues("""
                id,なまえ
                1,test
                2,test2
                3,test3
            """.trimIndent())
    
    csvFile.forEach {
        println("it = ${it}")
    }
    
}

data class CsvFile(
        val id:Long,
        val name:String
)

クォートで囲まれている要素の読み込み

QuoteCharでクォート文字を設定することで、その文字で囲まれている要素を読み込める。
fun main(args: Array) {
    val csvSchema = CsvSchema.builder()
            .setUseHeader(true)
            .setQuoteChar('"')
            .build()
    val csvMapper = CsvMapper()
    csvMapper.registerModule(KotlinModule())

    val csvFile = csvMapper.readerFor(CsvFile::class.java)
            .with(csvSchema)
            .readValues("""
                id,なまえ
                1,"test"
                2,"te""st2"
                3,"test3"
            """.trimIndent())
    
    csvFile.forEach {
        println("it = ${it}")
    }
    
}

data class CsvFile(
        val id:Long,
        @JsonProperty("なまえ")
        val name:String
)

Beanに定義されていないカラムを無視して読み込む

FAIL_ON_UNKNOWN_PROPERTIESをfalseにすることで、未定義のプロパティがあったときでも無視して読み込みが行われる。
fun main(args: Array) {
    val csvSchema = CsvSchema.builder()
            .setUseHeader(true)
            .setQuoteChar('"')
            .build()
    val csvMapper = CsvMapper().apply {
        registerModule(KotlinModule())
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    }

    val csvFile = csvMapper.readerFor(CsvFile::class.java)
            .with(csvSchema)
            .readValues("""
                id,なまえ,そのた
                1,"test",hoge
                2,"tes2",fuga
                3,"test3",piyo
            """.trimIndent())
    
    csvFile.forEach {
        println("it = ${it}")
    }
    
}

data class CsvFile(
        val id:Long,
        @JsonProperty("なまえ")
        val name:String
)