Vova Polischuk
Vova Polischuk

Reputation: 45

Scala Source.fromFile(fileName).getLines().next() misses second character in string line

Here is the code:

val bufferedSource = Source.fromFile("build.sbt")
val lines = bufferedSource.getLines()
bufferedSource.close()
ptintln(lines.next())

build.sbt file has such content:

name := "timeSeriesMerge"

version := "0.1"

scalaVersion := "2.11.8"

While debugging program in lines I get such string with second character missing:

"nme := "timeSeriesMerge""

Can anybody explain how is this possible? It misses the second character in the string. Where is the problem? It misses the second character for first line only.

It also would be cool if somebody could explain why this code throws:

java.io.IOException: Stream Closed

Upvotes: 0

Views: 2766

Answers (2)

chengpohi
chengpohi

Reputation: 14227

For your question 1, short answer: use Source.fromFile("build.sbt").getLines() directly without using bufferedSource, because bufferedSource and lines sharing same InputStream, in debug time, maybe the index has changed by toString

Full Explanation:

This is caused by toString method has changed the Stream's index that shared between lines and bufferedSource in the debug time , As we know when IDE stop in the breakpoint, it will invoke variable toString methods. like for lines and bufferedSource variables, it will invoke Iterator.toString, output like:

override def toString = (if (hasNext) "non-empty" else "empty")+" iterator"
> bufferedSource: non-empty iterator
> lines: non-empty iterator

As the above toString method, it will invoke hasNext firstly, this means it will invoke iter.hasNext in BufferedSource, but there is a problem for BufferedSource.iter:

  override lazy val iter = (
    Iterator
    continually (codec wrap charReader.read())
    takeWhile (_ != -1)
    map (_.toChar)
  )

when check hasNext it will read a character from InputStream. but this InputStream is sharing with BufferedLineIterator.

for val lines = bufferedSource.getLines() is creating new BufferedLineIterator from the BufferedSource by BufferedSource.decachedReader with sharing same InputStream between BufferedSource.

So if we have invoked hasNext method on BufferedSource, it will change the index on BufferedLineIterator.

Below is an example to demonstrate this:

  //file content: import Settings._
  val bufferedSource: BufferedSource = Source.fromFile("build.sbt")
  val lines = bufferedSource.getLines()
  bufferedSource.hasNext
  val str = lines.next()
  println(str)
  > mport Settings._

As the above example, we manually invoke hasNext method, so the Stream index has changed to next.

And for when we using IDE to debug, it invokes toString randomly, so it maybe cause the second character missing by debug in:

https://github.com/scala/scala/blob/2.13.x/src/library/scala/io/BufferedSource.scala#L55

Upvotes: 4

S.K
S.K

Reputation: 530

Here, You are calling "next" on Iterator after the stream has been closed.

You should close the stream only after you have done using it. Therefore, the correct sequence of statements should be

    println(lines.next())
    bufferedSource.close()

Also, if you want to iterate over the complete file, you need to call next inside a loop. You can try -

    for(line <- lines){
      println(line)
    }

Upvotes: 2

Related Questions