Fileの読み込み - Scala覚書
-
概要
Scalaでファイルを読み込む際の記述をいくつか並べてみる。個人的にはCommons IOのFileUtils.readLinesを使った時の記述が一番Scalaっぽいような気がする。
@Author mwSoft
@Date 2010/11/30
@Env Scala2.8 -
scala.io.Sourceで読む
もっとも基本的な感じがする記述。
// Sourceでファイル読み込み(1文字ずつ) var source = Source.fromFile("temp.txt") source.foreach(println) //=> t //=> e //=> s //=> t source.close // Sourceでファイル読み込み(1行ずつ) source = Source.fromFile("temp.txt") val lines = source.getLines lines.foreach(println) //=> test source.close // 文字コードは2つ目の引数に設定 source = Source.fromFile("temp.txt", "utf-8") val lines = source.getLines lines.foreach(println) //=> test source.close
3つ目の引数にバッファサイズを入れることもできる。その場合は1つ目の引数をjava.io.File型にする。でも指定してもそんなに速度が変わらなかった。
ところでScala2.8での上記の処理はやけに実行速度が遅い気がする。
具体的には、20MBくらいのファイルを読み込んだ場合に、scala.io.Sourceだと2352ミリ秒、JavaのBufferedReaderだと940ミリ秒。2.5倍ほど速度が違う。なんか速くする書き方とかあるのだろうか。
あと余談だけど、scala.io.SourceはURLも指定できる。
var source = Source.fromURL("http://www.mwsoft.jp/programming/scala/", "utf-8") val lines = source.getLines lines.foreach( println ) //=> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN... //=> <html> //=> <head> //=> <meta http-equiv="content-type" content="text/html; charset=utf-8"> //=> <title>Scala2.8覚書(mwSoft)</title> //=> <以下略> source.close
このように何かと便利なので、ケースバイケースで使いたいところ。
-
java.io.BufferedReaderで読む
Javaのファイル操作は何かと面倒。いろんな機能があるのはありがたいことではあるのだけど、書いていてたまにイジメられているような気持ちになる。
// FileをFileReaderで読み込んでBufferedReaderでラップする var reader = new BufferedReader( new FileReader( new File("temp.txt") ) ) var line:String = null while( { line = reader.readLine; line != null } ) { println( line ) } reader.close // 文字コードを指定して読み込む場合は、軽い嫌がらせのような記述になる var reader = new BufferedReader( new InputStreamReader( new FileInputStream( new File( "temp.txt" ) ), "utf-8" ) ) var line:String = null while( { line = reader.readLine; line != null } ) { println( line ) line = reader.readLine } reader.close
そんなわけで、私はファイルの読み書きはもっぱらCommonsに任せることにしている。
-
org.apache.commons.io.FileUtilsで読む
Commonsについての説明は、下記URL参照
http://www.mwsoft.jp/programming/scala/commons.htmlまずはcloseいらずの、一度にファイルを読み込んでしまう処理。
// readFileToStringはファイル全体を一度に読み込む val str = FileUtils.readFileToString( new File("temp.txt") ) println( str ) //=> test // JavaのClassをforeachするためにimportしておく import scala.collection.JavaConversions._ // readLinesは、読み込んだファイルを行で分けて、List
で結果を返す FileUtils.readLines( new File("temp.txt") ).foreach( println ) //=> test 大容量ファイル相手に実行すると死ねますが、普段はこれで十分かと。
次に1度にメモリに溜め込まずに、1行ずつ読み込んでいく記述。
// JavaのClassをforeachするためにimportしておく import scala.collection.JavaConversions._ // close必須なのでscala.io.Sourceの時のようにインスタンスは残しておく val ite = FileUtils.lineIterator( new File("temp.txt") ) ite.foreach( println ) //=> test ite.close // 文字コードを指定するのも簡単 val ite2 = FileUtils.lineIterator( new File("temp.txt"), "utf-8" ) ite2.foreach( println ) //=> test ite2.close
FileUtils.lineIteratorは内部的にはBufferedReaderで回しているので、速度はJavaで書いた時と変わらない。個人的には大きめのファイルを読む場合はたいていこれを使っている。