Search code examples
scalainputstreamfilereaderfromfile

scala BufferedSource Position


I have 2 questions about the Scala class BufferedSource.

How can I query the current reading position ?

I tried it with pos :

object testapp extends App {

 val doc = scala.io.Source.fromFile("text.txt")

 println(doc.pos)
 doc.next()
 println(doc.pos)
 doc.next()
 println(doc.pos)
 }

Output:

 0
 2049
 2050

Why it jumps from 0 to 2049 ?!

Is there another way to query the position and/or set it somewhere else ?

Thanks for your help :-)


Solution

  • pos returns position of last character returned by next(), but the trick is that position is a combination of row and column encoded by position's encoder (scala.io.Position) as a single Integer:

    The object Position provides convenience methods to encode * line and column number in one single integer. The encoded line * (column) numbers range from 0 to LINE_MASK (COLUMN_MASK), * where 0 indicates that the line (column) is undefined and * 1 represents the first line (column)...

    https://github.com/scala/scala/blob/v2.11.8/src/library/scala/io/Position.scala

    http://www.scala-lang.org/api/2.11.8/#scala.io.Source$RelaxedPosition$

    Use Postioner in order to get more readable info:

    The current input and position, as well as the next character methods delegate to the positioner.

    Example:

    val doc = scala.io.Source.fromFile("aaa.txt")
    val positioner =  new doc.Positioner()
    val positioned = doc.withPositioning(positioner)
    positioned.next()
    scala> positioner.cline -> positioner.ccol
    res15: (Int, Int) = (1,2)
    positioned.next()
    scala> positioner.cline -> positioner.ccol
    res17: (Int, Int) = (1,3)
    

    P.S. Source is intended for reading data as stream of characters, so it provides you conveniences like getLines() etc, so basically that's why Positioner works with rows and columns instead of an absolute position.

    If you need an Iterator that returns you an absolute position of every character, use zipWithIndex:

    scala> val doc = scala.io.Source.fromFile("aaa.txt").zipWithIndex
    doc: Iterator[(Char, Int)] = non-empty iterator
    
    scala> doc.next()
    res38: (Char, Int) = (a,0)
    
    scala> doc.next()
    res39: (Char, Int) = (a,1)
    
    scala> doc.next()
    res40: (Char, Int) = (a,2)
    
    scala> doc.next()
    res41: (Char, Int) = (a,3)
    
    scala> doc.next()
    res42: (Char, Int) =
    (
    ,4)