在Scala中,将整个文件读入内存的简单而规范的方法是什么?(理想情况下,可以控制字符编码。)

我能想到的最好的是:

scala.io.Source.fromPath("file.txt").getLines.reduceLeft(_+_)

或者我应该使用Java的一个可怕的习语,其中最好的(不使用外部库)似乎是:

import java.util.Scanner
import java.io.File
new Scanner(new File("file.txt")).useDelimiter("\\Z").next()

通过阅读邮件列表讨论,我甚至不清楚scala.io.Source是否应该是规范的I/O库。我不明白它的目的到底是什么。

... 我想要一些简单易记的东西。例如,在这些语言中,很难忘记成语……

Ruby    open("file.txt").read
Ruby    File.read("file.txt")
Python  open("file.txt").read()

当前回答

Java 8 +

import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Paths}

val path = Paths.get("file.txt")
new String(Files.readAllBytes(path), StandardCharsets.UTF_8)

Java 11 +

import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path}

val path = Path.of("file.txt")
Files.readString(path, StandardCharsets.UTF_8)

它们提供了对字符编码的控制,并且不需要清理资源。由于更高效的分配模式,它也比其他模式(例如getLines(). mkstring ("\n"))更快。

其他回答

Java 8 +

import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Paths}

val path = Paths.get("file.txt")
new String(Files.readAllBytes(path), StandardCharsets.UTF_8)

Java 11 +

import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path}

val path = Path.of("file.txt")
Files.readString(path, StandardCharsets.UTF_8)

它们提供了对字符编码的控制,并且不需要清理资源。由于更高效的分配模式,它也比其他模式(例如getLines(). mkstring ("\n"))更快。

(编辑:这在scala 2.9中不起作用,也许在2.8中也不起作用)

使用干:

scala> io.File("/etc/passwd").slurp
res0: String = 
##
# User Database
# 
... etc
val lines = scala.io.Source.fromFile("file.txt").mkString

顺便说一下,“scala.”并不是真正必要的,因为它总是在作用域中,当然,您可以完全或部分地导入io的内容,而不必在前面加上“io.”。

但是,上面的操作使文件保持打开状态。为了避免问题,你应该像这样关闭它:

val source = scala.io.Source.fromFile("file.txt")
val lines = try source.mkString finally source.close()

上面代码的另一个问题是,由于它的实现,它非常慢。对于较大的文件,应该使用:

source.getLines mkString "\n"

你可以使用

Source.fromFile(fileName).getLines().mkString

但是应该注意的是,getLines()删除了所有新的行字符。 如果你想保存格式,你应该使用

Source.fromFile(fileName).iter.mkString

在scala.io.Source上使用getLines()会丢弃用于行结束符的字符(\n, \r, \r\n等)。

下面应该保持字符对字符,并且不会进行过多的字符串连接(性能问题):

def fileToString(file: File, encoding: String) = {
  val inStream = new FileInputStream(file)
  val outStream = new ByteArrayOutputStream
  try {
    var reading = true
    while ( reading ) {
      inStream.read() match {
        case -1 => reading = false
        case c => outStream.write(c)
      }
    }
    outStream.flush()
  }
  finally {
    inStream.close()
  }
  new String(outStream.toByteArray(), encoding)
}