微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

scala – 迭代文件的行

我想写一个简单的函数,迭代文本文件的行.我相信2.8可以做到:

def lines(filename: String) : Iterator[String] = { 
    scala.io.source.fromFile(filename).getLines
}

就是这样,但在2.9中,上面的方法不起作用,而是我必须这样做:

def lines(filename: String) : Iterator[String] = { 
    scala.io.source.fromFile(new File(filename)).getLines()
}

现在,麻烦的是,我想在for comprehension中组合上面的迭代器:

for ( l1 <- lines("file1.txt"); l2 <- lines("file2.txt") ){ 
    do_stuff(l1,l2) 
}

这再次,曾经与2.8一起正常工作但导致“太多打开的文件
在2.9中被抛出的异常.这是可以理解的 – 第二行
在理解中最终打开(而不是关闭)每行的文件
在第一个.

在我的情况下,我知道“file1.txt”很大,我不想把它吸进去
内存,但第二个文件很小,所以我可以写一个不同的linesEager
像这样:

def linesEager(filename: String): Iterator[String] = 
    val buf = scala.io.source.fromFile(new File(filename))
    val zs  = buf.getLines().toList.toIterator
    buf.close()
    zs

然后把我的理解变成:

for (l1 <- lines("file1.txt"); l2 <- linesEager("file2.txt")){ 
    do_stuff(l1,l2) 
}

这有效,但显然很难看.有人可以建议制服和清洁
实现上述目标的方式.好像你需要一种迭代器的方法
文件到达结尾时,由行返回以关闭文件
这肯定发生在2.8,这就是为什么它在那里工作?

谢谢!

顺便说一句 – 这是显示问题的完整程序的最小版本:

import java.io.PrintWriter
import java.io.File

object Fail { 

  def lines(filename: String) : Iterator[String] = { 
    val f = new File(filename)
    scala.io.source.fromFile(f).getLines()
  }

  def main(args: Array[String]) = { 
    val smallFile = args(0)
    val bigFile   = args(1)

    println("helloworld")

    for ( w1 <- lines(bigFile)
        ; w2 <- lines(smallFile)
        ) 
    {
      if (w2 == w1){
        val msg = "%s=%s\n".format(w1,w2)
        println("found" + msg)
      }
    }

    println("goodbye")
  }

}

在2.9.0我用scalac WordsFail.scala编译然后我得到这个:

rjhala@goto:$scalac WordsFail.scala 
rjhala@goto:$scala Fail passwd words
helloworld
java.io.FileNotFoundException: passwd (Too many open files)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:120)
    at scala.io.source$.fromFile(Source.scala:91)
    at scala.io.source$.fromFile(Source.scala:76)
    at Fail$.lines(WordsFail.scala:8)
    at Fail$$anonfun$main$1.apply(WordsFail.scala:18)
    at Fail$$anonfun$main$1.apply(WordsFail.scala:17)
    at scala.collection.Iterator$class.foreach(Iterator.scala:652)
    at scala.io.BufferedSource$BufferedLineIterator.foreach(BufferedSource.scala:30)
    at Fail$.main(WordsFail.scala:17)
    at Fail.main(WordsFail.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:78)
    at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:24)
    at scala.tools.nsc.util.ScalaClassLoader$urlclassloader.asContext(ScalaClassLoader.scala:88)
    at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:78)
    at scala.tools.nsc.util.ScalaClassLoader$urlclassloader.run(ScalaClassLoader.scala:101)
    at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:33)
    at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:40)
    at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:56)
    at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:80)
    at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:89)
    at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

解决方法

scala-arm提供了一个很好的机制,可以在您完成资源时自动关闭资源.

import resource._
import scala.io.source

for (file1 <- managed(Source.fromFile("file1.txt"));
     l1 <- file1.getLines();
     file2 <- managed(Source.fromFile("file2.txt"));
     l2 <- file2.getLines()) {
  do_stuff(l1,l2)
}

但是,除非你在循环访问file1.txt时指望改变file2.txt的内容,否则最好在循环之前将其读入List.没有必要将其转换为迭代器.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐