LoginSignup
3
1

More than 5 years have passed since last update.

SXSSFSheet.getRow で NULLが返ってきてハマった話

Last updated at Posted at 2018-10-03

1. はじめに

私がscalaで実装したとある機能で、
ストリーミングで数百MBのエクセルファイルを作成しているのですが、
CSVも作って下さいとの事で、サクッと作ろうとしたら少しハマった話です。

1-1. 使っているライブラリ

org.apache.poi.xssf.streamingです。
メモリを喰わず高速でexcelファイルをアウトプットしてくれます。

2. ハマった内容

2-1. こんな関数を作りました。


  def convertToCsvStr(sheet: SXSSFSheet): String = {
    var csvStr: String = ""
    for (ri <- 0 to sheet.getLastRowNum()) {
      val row = sheet.getRow(ri)
      if (row != null) {
        for (ci <- 0 to row.getLastCellNum()) {
          val cellStr = if (row.getCell(ci) != null) {
            row.getCell(ci).toString()
          } else {
            ""
          }
          csvStr = csvStr + "\"" + cellStr + "\","
        }
      }
      csvStr = csvStr + "\r"
    }
    return csvStr
  }

作成したbookのオブジェクトからsheetオブジェクトを引っ張りだして、
その内容をこの関数にお渡しし、
csv用のstringオブジェクトを作るというもくろみです。

2-2. 発生した現象

80行分データがあるシートのからCSVを作る場合は特に問題なかったのですが、
158行データがあるシートだと、CSVの0-58行目が空っぽになってしまいました。
上記の関数を見ての通り、rowがnullの場合は改行しかしないので、
rowがnullになってやがるな!とデバッグを開始。

3. 原因

我がコードを疑い、ステップ実行してゴニョゴニョデバッグしたのですが、
ちゃんとcreateRow(0)している、nullになるはずのない、0行目のrowが、シートの作成が終わったあと参照してみるとnullになっている。なんでだよ。

それは仕様でした。。。

公式Document に記載されとりました。

SXSSFSheet.createRow でRowを作る際にフラッシュされていないレコードの総数が指定された値を超えると、インデックス値が最​​も低い行がフラッシュされ、SXSSFSheet.getRowでアクセスできなくなります。

When a new node is created via SXSSFSheet.createRow(int) and the total number of unflushed records would exceed the specified value, then the row with the lowest index value is flushed and cannot be accessed via SXSSFSheet.getRow(int) anymore.

flushする閾値は指定できる様ですが、
おとなしくデフォのまま、createRow,setCellValueした直後に、
csv用のstringにカンマ区切りで値をセットしようと思います。

メモリ節約のためにstreamingでファイル作成するライブラリなので、一定の行数になると変数の中をflushしてtmpファイルにそのデータを吐き出すんですねきっと。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1