【问题标题】:What's the right way to use scala.io.Source?使用 scala.io.Source 的正确方法是什么?
【发布时间】:2011-05-26 10:10:14
【问题描述】:

在许多示例中,描述了您可以使用scala.io.Source 来读取整个文件,如下所示:

val str = scala.io.Source.fromFile("test.txt").mkString()

但是没有提到关闭底层流。

为什么 Scala 不提供方便的方法来做到这一点,例如 Python 中的 with 子句?它看起来很有用,但并不难。

还有其他更好的方法可以在 Scala 中安全地做到这一点,我的意思是读取整个文件吗?

【问题讨论】:

  • 以这种方式使用Source而不关闭底层流是否正确?
  • 如果你阅读了scala.io.Source的代码,你会发现其实它把关闭底层流的工作交给了你。太棒了!
  • 考虑改用:import java.nio.file.{Files, Path, Path} val data = Files.readString(path)

标签: scala scala-2.8


【解决方案1】:

Scala 2.13 开始,标准库提供了一个专用的资源管理实用程序:Using

在这种情况下,它可以与scala.io.Source 一起使用,因为它扩展了AutoCloseable,以便从文件中读取,无论如何,之后关闭文件资源:

import scala.util.Using
import scala.io.Source

Using(Source.fromFile("file.txt")) { source => source.mkString }
// scala.util.Try[String] = Success("hello\nworld\n")

【讨论】:

  • 不错的语法,似乎很奇怪这种语言不得不等到这么晚才得到这个!
【解决方案2】:

为了完整起见

val testTxtSource = scala.io.Source.fromFile("test.txt")
val str = testTxtSource.mkString()
testTxtSource.close()

应该把事情做好。

【讨论】:

  • 不应该在try 块中和close()finally 块中吗?
  • @robinst 那将是一件好事,我同意丹尼尔的回答(即根本不使用 scala.io.Source)但是,它在我们不使用的 Dojos 中很有用编写生产代码。另外,我会使用 ARM 库(而不是 try catch),因为 close() 也可能引发异常,而且我发现在 finally 中包含 try catch finally 很尴尬。
  • 这种做法可能会导致资源泄露
【解决方案3】:

Scala 的io 库只是为有限的需求提供支持。有人努力为 Scala 提供一个经过深思熟虑的 io 库,该库目前托管在 assembla,还有一个 github 存储库。

如果您打算将 I/O 用于读取短暂进程中的临时文件之外的任何其他用途,您最好使用 Java 库,或者查看编译器中当前可用的 I/O 支持(其中将需要 scala-compiler.jar 与应用程序一起分发)。

自标准库 (scala.util.Using) 中的 Scala 2.13 起提供自动资源管理。对于较旧的 Scala 版本,请查看 this questionthis library(该问题的已接受答案中有特色)。

因此,在 Scala 2.13 或更高版本上,这可以正常工作:

import scala.util.Using
import scala.io.Source

val tryStr: Try[String] = Using(Source.fromFile("test.txt"))(_.mkString())

【讨论】:

  • 您是否仍然建议从 2016 年起不使用 scala.io?
  • @knub 我没有查看 Scala 2.12 是否有改进,但是,否则,是的,我支持同样的建议。
  • 在 2019 年,我仍然看到 Java NIO.2 包比 io.Source 包要复杂得多,以至于它保证使用 Java 库而不是纯 Scala 解决方案(如这让我很痛苦)。
  • 做类似 Using(new java.io.BufferedReader(new java.io.FileReader(infile)) { in => val data = in.lines().iterator( ).asScala // 在这里做点什么 ??? 需要进行很多转换才能将文件变成行流,最后变成可以执行标准 Scala 操作的形式。如果你想使用,有没有更好的方法现代 2.13 和 Java 11+?
  • @MurrayToddWilliams 最近的 Java 有更紧凑的方法,但这将是一个不同的问题。 Scala 2.13 向标准库添加了资源管理(请参阅stackoverflow.com/a/55440868/53013),这使得 Valentin Tihomirov (stackoverflow.com/a/33972743/53013) 提出的解决方案成为在 Scala 中执行此操作的实用方法。
【解决方案4】:

我推荐using the using,它可以让你的代码更整洁、更可靠

using(Source.fromFile("test.txt")){ _.mkString()}

Scala 2.13 将Using 添加到库中。因此,在 Using.apply 返回 Try 的条件下,在 Scala 2.13 上它变为:

import scala.util.Using
import scala.io.Source

Using(Source.fromFile("test.txt"))(_.mkString)

【讨论】:

  • @OsskarWerrewka mkString 没有副作用,所以括号应该省略,即using(Source.fromFile("test.txt")){ _.mkString}
猜你喜欢
  • 1970-01-01
  • 2021-11-24
  • 2021-09-23
  • 2017-04-07
  • 2013-01-09
  • 2013-03-19
  • 2019-05-11
  • 2018-02-17
  • 2022-01-07
相关资源
最近更新 更多