テキストファイルをオープンして内容を出力する

(この記事は Scala Advent Calendar jp 2010 : ATND の8日目です。)


scala.io.Source.fromFile」というのがあってそれが使えそうだった。

val filename = "test.txt"
scala.io.Source.fromFile(filename).getLines.foreach(println)

おおお簡単!と思ったんだけど、自動ではcloseしてくれないよね。
仕方なく自分でcloseする。

val filename = "test.txt"
val source = scala.io.Source.fromFile(filename)
try {
  source.getLines.foreach(println)
} finally {
  source.close
}

毎回これ書くのはめんどくさい。scalaが俺にユーティリティ関数を作れと囁いている。

def getLinesFromFile(filename: String, f:(String) => Unit) = {
  val source = scala.io.Source.fromFile(filename)
  try {
    source.getLines.foreach(f)
  } finally {
    source.close
  }
}
getLines("test.txt", println)

第一引数がファイル名、第二引数が実行させたい関数です。
で、scala.io.Sourceのソース読んだけど、FileInputStreamをラップしているような感じですね。


ただいま有志が逆引きScalaというTips集を作成しています。まだネタ不足気味なので、何かいいネタがあったら教えて下さい。


追記:こう書いた方がいいんじゃないかって話戴きました。ありがとうございます。自動的に閉じるSource - ( ꒪⌓꒪) ゆるよろ日記

  1. LoanPattern使って書く
  2. Iteratorに対して、そもそもSource自身が最後まで読んだら自動的に閉じる

build配下のプロジェクトクラス

import sbt._

class MyProject(info: ProjectInfo) extends DefaultProject(info) {
  override def libraryDependencies = Set(
    "net.databinder" %% "dispatch" % "0.7.7"
  ) ++ super.libraryDependencies
}

検索するサンプル

import dispatch._
import dispatch.twitter._
import twitter.{Auth,Status}
import oauth._
import oauth.OAuth._

object SearchSample {
  def main(args: Array[String]): Unit = {

    val searchWord = "rpscala"   

    val http = new Http
    val tweets = http(Search(searchWord).product)
    val message = tweets.reverse.map { js =>
      val Search.text(text) = js
      val Search.from_user(from_user) = js
      (Status.rebracket(text), from_user)
    }

    message.foreach({x => println(x._2 + " " + x._1)})
  }
}

TLを取得

import dispatch._
import dispatch.twitter._
import twitter.{Auth,Status}
import oauth._
import oauth.OAuth._

import info.growl.{Growl, GrowlUtils}
import java.io.File
import javax.imageio.ImageIO

object FriendsTimeline {
  val CONSUMER_KEY = "xxxxxxxxxxxxxx"
  val CONSUMER_SECRET = "xxxxxxxxxxxxxx"
  val ACCESS_TOKEN = "xxxxxxxxxxxxxx"
  val ACCESS_TOKEN_SECRET = "xxxxxxxxxxxxxx"

  def main(args: Array[String]): Unit = {
    val http = new Http
    val CONSUMER = Consumer(CONSUMER_KEY, CONSUMER_SECRET)

    val map = Map("oauth_token"->ACCESS_TOKEN, "oauth_token_secret"->ACCESS_TOKEN_SECRET)
    val token = Token.apply(map)
    val tweets = http(Status.friends_timeline(CONSUMER, token.get).product)
    val message = tweets.reverse.map { js =>
      val Status.user.screen_name(screen_name) = js
      val Status.text(text) = js
      (Status.rebracket(text), screen_name)
    }

    // http://d.hatena.ne.jp/yuroyoro/20090724/1248431961
    growl(message)
  }

  def growl(message: List[(String, String)]): Unit = {
    val appName = "How do you like wednesday Growl"
    val notificationName = "How do you like wednesday Growl"
    val growl:Growl  = GrowlUtils.getGrowlInstance( appName )
    growl.addNotification(notificationName , true)
    growl.register()

    message.foreach({
      x =>
      println(x._2 + " " + x._1)
      growl.sendNotification(notificationName ,  x._2,  x._1)
    })
  }
}

Mapの初期化

var map = Map("k1"->"v1", "k2"->"v2")

ちなみに「"k1"->"v1"」の部分はタプルと言うらしい。
値の追加

map += "k3"->"v3"

取得

map.get("k1")

res1: Option[java.lang.String] = Some(v1)
map.get("k1").get

res2: java.lang.String = v1
map.getOrElse("k1", "not found")

res3: java.lang.String = v1
map.getOrElse("k4", "not found")

res4: java.lang.String = not found

Liftにライブラリを追加

project/build/LiftProject.scalaに追加

override def libraryDependencies = Set(
  "net.liftweb" %% "lift-webkit" % liftVersion % "compile->default",
  "net.liftweb" %% "lift-mapper" % liftVersion % "compile->default",
  "org.mortbay.jetty" % "jetty" % "6.1.22" % "test->default",
  "junit" % "junit" % "4.5" % "test->default",
  "org.scala-tools.testing" %% "specs" % "1.6.5" % "test->default",
  "com.h2database" % "h2" % "1.2.138",
  "net.databinder" %% "dispatch" % "0.7.7"
) ++ super.libraryDependencies

%と%%の違いは正直よくわかっていない。