如何逐行从标准输入读取数据?

93

如何使用Scala从标准输入逐行读取数据?类似于Java中的等效代码:

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());
        }
    }
}
6个回答

132

最直观的方法是使用Predef中的readLine()。然而,这样做相当丑陋,因为您需要检查最终的null值:

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

这太啰嗦了,你最好使用java.util.Scanner

我认为更优美的方法是使用scala.io.Source

object ScannerTest {
  def main(args: Array[String]) {
    for (ln <- io.Source.stdin.getLines) println(ln)
  }
}

4
自2.11.0版本起,Predef的readLine方法已被弃用,现在建议使用scala.io.StdIn中的方法。 - nicolastrres
1
@itemState 我的程序不会结束,如果我使用"io.Source.stdin.getLines",它会进入等待模式...我该如何处理这个问题... - Raja

54

对于控制台,您可以使用Console.readLine。您可以这样写(如果要在空行上停止):

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

如果你要使用cat命令生成输入,那么你可能需要使用以下命令来停止输入:

@inline def defined(line: String) = {
  line != null && line.nonEmpty
}
Iterator.continually(Console.readLine).takeWhile(defined(_)).foreach(line => println("read " + line))

我知道关于Console.readLine()的用法,我正在寻找从标准输入逐行读取的“scala”方式。 - Andrei Ciobanu
11
我认为您的意思是 takeWhile(_ != null),意思是取出满足条件“不为 null”的元素。 - Seth Tisue
1
取决于你想要如何停止。寻找空行通常是最简单的解决方案。 - Landei
6
请注意,从Scala 2.11.0开始,Console.readLine已被弃用,请改用StdIn.readline - Bartłomiej Szałach
或者使用.takeWhile(Option(_).nonEmpty)可能会更好,以避免完全使用null关键字。 - conny

27
val input = Source.fromInputStream(System.in);
val lines = input.getLines.collect

6
io.Source.stdin被定义在scala.io.Source类中,表示从标准输入读取数据的方法。因此,最好使用io.Source.stdin来读取标准输入。 - Nader Ghanbari
这似乎无法在Scala 2.12.4中工作,或者我没有找到正确的导入内容。 - akauppi
它在Scala 2.12中可以工作,只是collect方法自从这个答案以来已经改变,所以你只需要调用input.getLines,它会给你一个Iterator。你可以使用.toStream.toList强制将其实现,具体取决于用例。 - Nader Ghanbari

12

递归版本(编译器检测到尾递归,以提高堆使用效率),

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

注意在Scala 2.11 中使用io.StdIn。同时请注意,通过这种方法,我们可以将用户的输入积累到一个集合中,并最终返回它--除了被打印出来。也就是说,

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]())
}

10

你不能使用

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

在这里可以找到: Scaladoc API


这是与循环结构不同的代码。 - techkuz

2

如其他评论中简要提到的那样,自Scala 2.11.0起,scala.Predef.readLine()已被弃用,您可以使用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 != "")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接