92

What's the Scala recipe for reading line by line from the standard input ? Something like the equivalent java code :

import java.util.Scanner; 

public class ScannerTest {
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            System.out.println(sc.nextLine());
        }
    }
}
Jacek Laskowski
  • 64,943
  • 20
  • 207
  • 364
Andrei Ciobanu
  • 11,585
  • 20
  • 75
  • 115

6 Answers6

131

The most straight-forward looking approach will just use readLine() which is part of Predef. however that is rather ugly as you need to check for eventual null value:

object ScannerTest {
  def main(args: Array[String]) {
    var ok = true
    while (ok) {
      val ln = readLine()
      ok = ln != null
      if (ok) println(ln)
    }
  }
}

this is so verbose, you'd rather use java.util.Scanner instead.

I think a more pretty approach will use scala.io.Source:

object ScannerTest {
  def main(args: Array[String]) {
    for (ln <- io.Source.stdin.getLines) println(ln)
  }
}
Erik Kaplun
  • 33,421
  • 12
  • 92
  • 102
itemState
  • 1,346
  • 1
  • 8
  • 3
  • 3
    the method readLine of Predef was deprecated since 2.11.0, now it's recommended to use the method in `scala.io.StdIn` – nicolastrres Jun 08 '18 at 18:59
  • 1
    @itemState my program is not ending, if i use, "io.Source.stdin.getLines" going to wait mode ... how do handle this... – Raja Aug 12 '19 at 15:15
53

For the console you can use Console.readLine. You can write (if you want to stop on an empty line):

Iterator.continually(Console.readLine).takeWhile(_.nonEmpty).foreach(line => println("read " + line))

If you cat a file to generate the input you may need to stop on either null or empty using:

@inline def defined(line: String) = {
  line != null && line.nonEmpty
}
Iterator.continually(Console.readLine).takeWhile(defined(_)).foreach(line => println("read " + line))
simbo1905
  • 5,085
  • 1
  • 44
  • 67
Landei
  • 52,346
  • 12
  • 89
  • 188
27
val input = Source.fromInputStream(System.in);
val lines = input.getLines.collect
Jason
  • 1,226
  • 12
  • 23
  • 6
    `io.Source.stdin` is defined (in `scala.io.Source` class) as `def stdin = fromInputStream(System.in)` so probably it's better to stick with the `io.Source.stdin`. – Nader Ghanbari Oct 26 '14 at 15:38
  • This doesn't seem to work with Scala 2.12.4, or I didn't find the right things to import. – akauppi Feb 19 '18 at 13:46
  • It works in Scala 2.12, just that the `collect` method is changed sicne this answer so you have to just call `input.getLines` which gives you an `Iterator`. You can force it to materialize using `.toStream` or `.toList` on it, depends on the use case. – Nader Ghanbari Nov 06 '18 at 20:33
11

A recursive version (the compiler detects a tail recursion for improved heap usage),

def read: Unit = {
  val s = scala.io.StdIn.readLine()
  println(s)
  if (s.isEmpty) () else read 
}

Note the use of io.StdIn from Scala 2.11 . Also note with this approach we can accumulate user input in a collection that is eventually returned -- in addition to be printed out. Namely,

import annotation.tailrec

def read: Seq[String]= {

  @tailrec
  def reread(xs: Seq[String]): Seq[String] = {
    val s = StdIn.readLine()
    println(s)
    if (s.isEmpty()) xs else reread(s +: xs) 
  }

  reread(Seq[String]())
}
elm
  • 18,533
  • 11
  • 59
  • 106
10

Can you not use

var userinput = readInt // for integers
var userinput = readLine 
...

As available here : Scaladoc API

kaning
  • 137
  • 2
  • 7
2

As noted briefly in other comments, scala.Predef.readLine() is deprecated since Scala 2.11.0, and you can replace it with scala.io.StdIn.readLine():

// Read STDIN lines until a blank one
import scala.io.StdIn.readLine

var line = ""
do {
  line = readLine()
  println("Read: " + line)
} while (line != "")
Brad Solomon
  • 29,156
  • 20
  • 104
  • 175