さっしーブログ

埼玉県在住のシステムエンジニアです。基本的には技術的な内容を中心に発信していきます。

Scalaでコンソールにプログレスバーを表示する方法

マイグレーションツールを作成したときに、
本番並みのデータがデータベースに格納されていると処理に時間がかかり
コンソール上で動いているのか動いていないのかが心配だったため、
プログレスバーを表示してみることにした。

サンプルコードは以下。

object sample {

  def main(args: Array[String]): Unit = {
    val n: Int = 500000
    printProgressBar(n, {
      //・・・・何らかしらの処理
    })
  }

  private def printProgressBar(targetProcNum: Int, process: => Unit) = {
    for (i <- 0 to targetProcNum) {
      process
      val t: Double = (i.toDouble / targetProcNum.toDouble) * 100
      printf("=%% [%-100s] %s\r", t.toInt, "="*t.toInt, i + "/" + targetProcNum)
      System.out.flush()
    }
    println("")
  }
}

データ数は50万で設定している。

また、プログレスバーの実装はprintProgressBar1内に記述している。

以下の部分でプログレスバーを作っている。

printf("=%% [%-100s] %s\r", t.toInt, "="*t.toInt, i + "/" + targetProcNum)

このコードの説明はprintfの調査すればどのような出力を行っているかがわかるため説明は割愛する。
しかし、以下の部分は本記事のプログレスバーの出力の値に関係するのでざっくり説明すると

t.toInt

の部分は、処理全体の進捗をパーセンテージで出力するために進捗率の値を整数値で設定している。

 "="*t.toInt

の部分は、進捗バーを表現している。
進捗率に合わせて「=」の出力を何個表示すればよいかを進捗率の値で積算している。

 i + "/" + targetProcNum

の部分は、処理件数を全体に対して何件処理しているかを出力するために設定している。

プログレスバーを実装するにあたっては以下がもっとも重要

System.out.flush()

これを呼び出すことによって出力をバッファにためってカーソルを先頭に戻している。

ポイント①としては、printlnなどの改行を行うやつでプログレスバーを作ってはいけないこと。
ポイント②としては、もし処理実行の途中からflushが効かなくなった場合はコンソールのバッファーサイズを増やしてみてください。

以上