S-JIS[2011-02-27/2011-08-31] 変更履歴

Scala テキストファイル操作

Scalaでは、テキストファイルを読み込むのにscala.io.Sourceオブジェクトを使用する。


テキストファイルの読み込み

テキストファイルを読み込むにはfromFile()メソッドを使用する。(Scala2.8)

import scala.io.Source
val s = Source.fromFile("C:/temp/abc.txt")
try {
  for (line <- s.getLines) {
    println(line)
  }
} finally {
  s.close
}

fromFile()の第2引数でファイルのエンコーディング(文字コード)を指定することも出来る。

val s = Source.fromFile("C:/temp/abc.txt", "MS932")

(ファイル名を指定するときに"""を使うとWindowsのパス区切りに「\」が使いやすいが、uで始まるファイル名やディレクトリー名でハマるので、過信はしない方がいい)

fromFile()で返されるSource(実際はBufferedSource)は、Char(文字)の並び。
getLines()メソッドを呼び出すと行毎の文字列(String)の並びになる。


SourceおよびgetLines()で返されるイテレーターは、一度しか使えない(繰り返し使うことは出来ない)。

scala> val s = Source.fromFile("C:/temp/abc.txt")
s: scala.io.BufferedSource = non-empty iterator

scala> s.isTraversableAgain
res1: Boolean = false

scala> s.size
res2: Int = 2395

scala> s.size
res3: Int = 0

scala> s.getLines.foreach{ println(_) }
					←何も出ない

sizeメソッドの内部実装は、全てのデータを読み込んで文字数を数えるようになっている。
全て読み込んでしまうので、イテレーターはファイルの末尾を指す状態になり、再度sizeを呼び出しても(もう読み込めるものが無いので)0を返す。
この状態から文字列を取得しようとしても無理(何も返ってこない)。

したがって、読み込んだ結果を繰り返し使用したい場合はtoListメソッド等を使って変換しておく。

val s = Source.fromFile("C:/temp/abc.txt")
val list = try s.getLines.toList finally s.close

Scala2.9.0のREPLでは、Sourceの生成とその後の操作を2行に分けて実行すると、結果が空になる。[2011-06-05]
Scala2.9.1-finalで直った。[2011-08-31]

Scala 備考
scala> val s = Source.fromFile("C:/temp/a2.txt")
s: scala.io.BufferedSource = non-empty iterator

scala> val r = s.getLines.toList
r: List[String] = List()
2行に分けて実行すると、結果が空。
scala> val s = Source.fromFile("C:/temp/a2.txt");val r = s.getLines.toList
s: scala.io.BufferedSource = empty iterator
r: List[String] = List(aaa, aa)
scala> val r = Source.fromFile("C:/temp/a2.txt").getLines.toList
r: List[String] = List(aaa, aa)
1行で実行すると大丈夫。
scala> val s = Source.fromFile("C:/temp/a2.txt")
s: scala.io.BufferedSource = non-empty iterator

scala> val r = s.getLines.toList
r: List[String] = List(aaa, aa)
Scala2.8.1-final・2.9.1-finalだと大丈夫。[/2011-08-31]

Scala目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま