for-comprehension,guard和RandomAccessFile.readLine

时间:2016-11-15 21:46:16

标签: scala for-loop randomaccessfile for-comprehension

请考虑以下事项:

有一个包含一定行数的文本文件,例如:

  

的test.txt:       一个       b       C       d       Ë       F       G       ħ

(每个都在自己的行中)

然后有以下用于解析的类:

class MyAwesomeParser
{
    def parse(fileName: String, readLines: Int): IndexedSeq[String] =
    {
        val randomAccessFile = new RandomAccessFile(fileName, "r")

        val x: IndexedSeq[String] = for
        {
            x <- 0 until readLines
            r = randomAccessFile.readLine()
        } yield r

        x
    }
}

以下是测试:

class MyAwesomeParserTest extends WordSpec
{
    "MyAwesomeParser" when {
    "read" should {
      "parse only specified number of lines" in {
        val parser = new EdgeParser("")
        val x = parser.parse("test.txt", 5)

        assert(x.size == 5)
      }
    }

    "MyAwesomeParser" when {
    "read" should {
      "parse only until end of file" in {
        val parser = new EdgeParser("")
        val x = parser.parse("test.txt", 10)

        assert(x.size == 8)
      }
    }
  }
}

第二次测试是有问题的。当然,你说,你在这里错过了一名警卫......好吧,如果我加上

x <- 0 until readLines if randomAccessFile.readLine != null

到实现然后它会跳过几行,因为readLine已经消耗了这一行。

  r = randomAccessFile.readLine
  x <- 0 until readLines if r != null

不会遗憾地工作,因为第一行必须分配才能理解。

现在我想知道,是否有可能在理解之前循环直到给定的时间或者在基于readLine != null条件之前停止?

我的语法坏了吗?

2 个答案:

答案 0 :(得分:3)

如果您想坚持使用parse方法,可以使用getFilePointerlength

def parse(fileName: String, readLines: Int): IndexedSeq[String] =
{
    val randomAccessFile = new RandomAccessFile(fileName, "r")

    val x: IndexedSeq[String] = for
    {
        x <- 0 until readLines if randomAccessFile.getFilePointer < randomAccessFile.length
        r = randomAccessFile.readLine()
    } yield r

    x
}

但是,我建议您只使用scala.io.Source

,而不是重新发明轮子
def parse(fileName: String, readLines: Int): Iterator[String] =
  Source.fromFile(fileName).getLines.take(readLines)

答案 1 :(得分:2)

您可以将randomAccessFile.readLine封装在Option中,以便将null更改为None,将value更改为Some(value)

此外,Option可以被视为一个集合,因此您可以将其置于与IndexedSeq相同的理解中:

for {
  x <- 0 until readLines
  r <- Option(randomAccessFile.readLine())
} yield r