【问题标题】:how to close stream associated w/ iterator returned by Source.fromFile("/tmp/foo").getLines()如何关闭与 Source.fromFile("/tmp/foo").getLines() 返回的迭代器相关的流
【发布时间】:2015-09-16 03:00:00
【问题描述】:

我需要使用 Source.getLines() 创建一个迭代器,并快速查看 Scala源代码,在运行一些测试后,迭代器似乎没有关闭 即使在迭代器耗尽之后(即,在 hasNext() 开始为假之后)。

我想知道 Scala 推荐的关闭/释放用于创建迭代器的资源的技术是什么。我发现 一个有趣的库,似乎可以解决问题:

https://github.com/jsuereth/scala-arm

但是,我更喜欢使用核心 scala 库而不是 如果可能的话,拉入第 3 方的东西。如果你感兴趣 在我如何测试这个(在 Linux 上使用 'lsof' 列出打开的文件)中,我的 代码如下:

        object Test extends App {
          import sys.process._
          import scala.io.Source._


          "echo hello world" #> new java.io.File("/tmp/testing") !

          val  src = fromFile("/tmp/testing")
          val iter: Iterator[String] = src.getLines()
          while (iter.hasNext) {
            println("line=" + iter.next())
          }

          println("iterator exhausted.. sleeping while we check if file is still open using lsof")
          Thread.sleep(200000)
        }

运行程序后仍然处于休眠状态,运行以下命令:

 lsof   | grep /tmp/testing

你可能会看到这样的输出:

java  15813 ...253,0.... 12 .. lots-of-othernumbers..0462 /tmp/testing

然后当程序终止时,grep 将变为空(如您所想)。

提前感谢您提供的任何提示!

【问题讨论】:

    标签: scala iterator inputstream


    【解决方案1】:

    这是我倾向于使用的模式:

    def using[R <: Closeable, T](stream: R)(f: R => T): T =
      try {
        f(stream)
      } finally {
        stream.close()
      }
    

    你可以这样使用:

    def readSomeLines(is: InputStream) = {
      using(new BufferedReader(new InputStreamReader(is))) { stream =>
        Iterator.continually(stream.readLine().takeWhile(_ != null)).foreach(println)
      }
    }
    
    readSomeLines(new FileInputStream("/tmp/foo"))
    

    【讨论】:

      【解决方案2】:

      基于先前的答案,我建议将声明资源(例如打开文件)和执行工作都包装到 Scala Try 构造中:

        def using[R <: Closeable, T](uri: String)(claimResource: String => R)(work: R => Try[T]): Try[T] = {
          Try(claimResource(uri)) match {
            case Success(resource) => try { work(resource) } finally { resource.close }
            case Failure(f) => Failure(f)
          }
        }
      
        def countLines(s: Source): Try[Int] =
          Try(s.getLines().size)
      
        def main(args: Array[String]): Unit = {
          val fileName = """/path/to/file"""
          using(fileName)(Source.fromFile(_))(countLines) match {
            case Success(lc) => println(s"File '$fileName' has $lc lines")
            case Failure(f) => println(s"Failure: $f")
          }
        }
      

      【讨论】:

        猜你喜欢
        • 2013-03-08
        • 1970-01-01
        • 2014-10-31
        • 1970-01-01
        • 1970-01-01
        • 2016-03-16
        • 1970-01-01
        • 2017-08-06
        • 1970-01-01
        相关资源
        最近更新 更多