🐷

ScalaでCSVエクスポート処理する際の実装比較

2023/12/08に公開

はじめに

こんにちは。計測プラットフォーム開発本部バックエンドブロックのディーノです。普段は ZOZOMAT,ZOZOGLASS,ZOZOFIT といった計測技術に関わるシステムの開発、運用に携わっています。

下記会社説明資料の 11 ページ目に計測技術の紹介があるのでご興味あれば覗いてください。

本記事は、Scala で CSV エクスポート処理を代表的なライブラリで実装し、それぞれの記述を比較してみた。という入門編記事です。

要約

  • scala-csv, Apache Commons CSV, opencsv を使って CSV エクスポート処理を比較
  • scala-csv, Apache Commons CSV は Seq で CSV を書き込むことができたが、opencsv は Array で書き込む
  • Apache Commons CSV は CSV Format として、EXCEL 形式を指定できる

エクスポートしたい CSV

名前 身長 体重
曾々栗太郎 160 50
曾々栗次郎 180 70

scala-csv

実装

//> using dep com.github.tototoshi::scala-csv::1.3.10

import com.github.tototoshi.csv._
import java.io.File

case class Person(name: String, height: Int, weight: Int)

val persons = Seq(
  Person("曾々栗太郎", 160, 50),
  Person("曾々栗次郎", 180, 70),
)
val f = new File("out.csv")
val writer = CSVWriter.open(f)

writer.writeRow(Seq("名前", "身長", "体重"))

persons.foreach { p =>
  writer.writeRow(Seq(p.name, p.height, p.weight))
}

writer.close()

動作確認

scala-cli scala-csv-sample.sc
 Compiling project (Scala 3.3.1, JVM (14))
 Compiled project (Scala 3.3.1, JVM (14))
bat out-scala-csv.csv
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: out-scala-csv.csv
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ 名前,身長,体重
   2   │ 曾々栗太郎,160,50
   3   │ 曾々栗次郎,180,70
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────

所感

Scala のライブラリということもあり、比較した 3 つの中で 1 番自然に実装ができた。

Apache Commons CSV

実装

//> using dep org.apache.commons:commons-csv:1.10.0

import org.apache.commons.csv.{CSVFormat, CSVPrinter}
import java.io.{File, PrintWriter}

case class Person(name: String, height: Int, weight: Int)

val persons = Seq(
  Person("曾々栗太郎", 160, 50),
  Person("曾々栗次郎", 180, 70),
)
val printer = CSVPrinter(
  new PrintWriter(new File("out-commons-csv.csv")),
  CSVFormat.Builder.create(CSVFormat.DEFAULT)
    .setHeader("名前", "身長", "体重")
    .build()
)

persons.foreach { p =>
  printer.printRecord(p.name, p.height, p.weight)
}

printer.flush()
printer.close()
val printer = CSVPrinter(
  new PrintWriter(new File("out-commons-csv.csv")),
  CSVFormat.Builder.create(CSVFormat.DEFAULT)
    .setHeader("名前", "身長", "体重")
    .build()
)

動作確認

scala-cli commons-csv-sample.sc
Compiling project (Scala 3.3.1, JVM (14))
Compiled project (Scala 3.3.1, JVM (14))
bat out-commons-csv.csv
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: out-commons-csv.csv
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ 名前,身長,体重
   2   │ 曾々栗太郎,160,50
   3   │ 曾々栗次郎,180,70
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────

所感

実装のCSVFormat.Builder.create(CSVFormat.DEFAULT) 部分で RFC4180形式や Excel 形式を指定できるのがわかりやすかった。

opencsv

実装

//> using dep com.opencsv:opencsv:5.9

import java.io.{File, FileWriter}
import com.opencsv.CSVWriter

case class Person(name: String, height: Int, weight: Int)

val persons = Seq(
  Person("曾々栗太郎", 160, 50),
  Person("曾々栗次郎", 180, 70),
)

val f = new File("out-opencsv.csv")
val writer = new CSVWriter(new FileWriter(f))

writer.writeNext(Array("名前", "身長", "体重"))

persons.foreach { person =>
  writer.writeNext(Array(person.name, person.height.toString, person.weight.toString))
}

writer.close()

動作確認

scala-cli opencsv-sample.sc
Compiling project (Scala 3.3.1, JVM (14))
Compiled project (Scala 3.3.1, JVM (14))
bat out-opencsv.csv
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: out-opencsv.csv
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────
   1"名前","身長","体重"
   2"曾々栗太郎","160","50"
   3"曾々栗次郎","180","70"
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────

所感

比較した他のライブラリと違い、行の書き込みには Array[Any]で値を渡す必要があった。
また、書き込む値の型を String 形式に明示的に変換する必要があり少し面倒に感じた。

最後に

今回は、Scala で CSV エクスポート機能を実装する際のライブラリ比較をしました。Scala でシンプルに実装したい場合は scala-csv か Apache Commons CSV を選択するとよさそうに感じました。また、Excel でも 出力した CSV を開く必要がある場合は、Apache Commons CSV はがよりユースケースに沿うことができると感じました。理由は CSVFormat として明示的に Excel Format を選択できるためです。

We are hiring!

計測プラットフォーム部バックエンドブロックは、海外の研究開発チームと協働しながら 0→1 のプロダクト開発に取り組んでいます。少しでも興味を持っていただいた方は下記 Wantedly ページで私たちの取り組んでいる課題や技術スタックなど知っていただけると嬉しいです。

https://www.wantedly.com/projects/1142868

カジュアル面談も上記 Wantedly ページにて絶賛募集中ですので気軽に面談を申し込んでください!現場のエンジニアが面談に参加するのでより突っ込んだ話ができますのでぜひ活用ください。

明日は @ssssota さんです。

GitHubで編集を提案
株式会社ZOZO

Discussion