scala/basic

apache poi 를 사용해 scala 에서 Excel 파일 읽기

wefree 2021. 10. 14. 11:17
  def main(args: Array[String]): Unit = {
    val rows = readSheet[MyModel]("c:/work/input.xlsx", "평가 항목", true)
    println(rows)
  }

문제

apache poi 를 사용해 Excel 파일을 읽어보자. apache poi 는 자바 라이브러리지만 스칼라 스타일로 코딩해 보도록 한다.

 

코드

일반적으로 사용할 수 있도록 아래처럼 Generic 한 util 을 작성한다.

import org.apache.poi.openxml4j.opc.OPCPackage
import org.apache.poi.ss.usermodel.{Row, Workbook}
import org.apache.poi.xssf.usermodel.XSSFWorkbook

import java.io.File
import scala.collection.JavaConverters._

trait RowConverter[A] {
  def from(row: Row): A
}

object ExcelUtil {
  def readSheet[A: RowConverter](path: String, sheetName: String, hasHeader: Boolean): Seq[A] = {
    val rowConverter = implicitly[RowConverter[A]]

    val pkg                = OPCPackage.open(new File(path))
    val workbook: Workbook = new XSSFWorkbook(pkg)

    val sheet               = workbook.getSheet(sheetName)
    val rows: Iterator[Row] = sheet.iterator().asScala

    // header 제거
    val convertedRows: Seq[A] = rows
      .filterNot(hasHeader && _.getRowNum == 0)
      .map(rowConverter.from)
      .toList

    workbook.close()
    pkg.close()
    convertedRows
  }
}

 

사용 목적에 맞게 모델링 하고, implicit instance 를 구현해 준다.

import org.apache.poi.ss.usermodel.Row

case class MyModel(
  no: Int,
  keyword: String,
  residence: Option[String]
)

object MyModel {
  implicit val rowConverterInstance: RowConverter[MyModel] = new RowConverter[MyModel] {
    override def from(row: Row): MyModel = {
      val no         = row.getCell(0).getNumericCellValue.toInt
      val keyword    = row.getCell(1).getStringCellValue
      val residence  = Option(row.getCell(2)).map(_.getStringCellValue)
      MyModel(no, keyword, residence)
    }
  }
}

 

마지막으로 아래처럼 사용하면 된다.

  def main(args: Array[String]): Unit = {
    val convertedRows: Seq[MyModel] = readSheet[MyModel]("c:/now/input.xlsx", "평가 항목", true)
    println(convertedRows)
  }