在Scala中读取整个文件?

在Scala中读取整个文件?,scala,Scala,在Scala中,将整个文件读入内存的简单规范方法是什么?(理想情况下,可以控制字符编码。) 我能想到的最好办法是: scala.io.Source.fromPath("file.txt").getLines.reduceLeft(_+_) 或者我应该使用其中一个,其中最好的(不使用外部库)似乎是: import java.util.Scanner import java.io.File new Scanner(new File("file.txt")).useDelimiter("\\Z").

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

我能想到的最好办法是:

scala.io.Source.fromPath("file.txt").getLines.reduceLeft(_+_)
或者我应该使用其中一个,其中最好的(不使用外部库)似乎是:

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()
顺便说一句,“
scala.
”并不是真的必要,因为它始终在范围内,当然,您可以全部或部分导入io的内容,也可以避免预先添加“io”

但是,上述操作会使文件保持打开状态。为避免出现问题,应按如下方式关闭:

val source = scala.io.Source.fromFile("file.txt")
val lines = try source.mkString finally source.close()
上面代码的另一个问题是,由于其实现性质,它的速度非常慢。对于较大的文件,应使用:

source.getLines mkString "\n"

明显的问题是“为什么要读取整个文件?”如果文件变得非常大,这显然不是一个可伸缩的解决方案。
scala.io.Source
getLines
方法返回了一个
Iterator[String]
,非常有用且简洁


使用底层java IO实用程序将
文件
读取器
InputStream
转换为
字符串
,实现隐式转换并不是一件容易的事。我认为缺乏可伸缩性意味着他们不将其添加到标准API中是正确的

为了扩展Daniel的解决方案,您可以将以下导入插入任何需要文件操作的文件中,从而大大缩短时间:

import scala.io.Source._
使用此功能,您现在可以执行以下操作:

val lines = fromFile("file.txt").getLines
我会小心将整个文件读入单个
字符串
。这是一个非常坏的习惯,它会比你想象的更快更严重地伤害你。
getLines
方法返回类型为
Iterator[String]
的值。它实际上是一个懒散的文件游标,允许您只检查所需的数据,而不必冒内存过剩的风险


哦,为了回答您关于
源代码
的隐含问题:是的,它是规范的I/O库。大多数代码最终使用
java.io
,因为它的接口级别较低,与现有框架的兼容性更好,但是任何有选择的代码都应该使用
Source
,特别是对于简单的文件操作。

我被告知Source.fromFile有问题。就个人而言,我在使用Source.fromFile打开大型文件时遇到问题,不得不求助于Java InputStreams

另一个有趣的解决方案是使用scalax。下面是一个注释良好的代码示例,该代码使用ManagedResource打开日志文件以使用scalax helpers打开文件:

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

使用主干:

scala> io.File("/etc/passwd").slurp
res0: String = 
##
# User Database
# 
... etc
正如前面提到的几个人一样,由于连接泄漏,最好避免使用

在新孵化器项目(即scala io)合并之前,scalax和纯java LIB(如commons io)可能是最好的选择。

在scala.io.Source上使用getLines()将丢弃用于行终止符的字符(\n、\r、\r\n等)

以下内容应逐字符保留,并且不会进行过多的字符串连接(性能问题):


打印每一行,如使用Java BufferedReader读取服务器行,然后打印:

scala.io.Source.fromFile("test.txt" ).foreach{  print  }
等价物:

scala.io.Source.fromFile("test.txt" ).foreach( x => print(x))

您还可以使用scala io的路径来读取和处理文件

import scalax.file.Path
现在,您可以使用以下命令获取文件路径:-

val filePath = Path("path_of_file_to_b_read", '/')
val lines = file.lines(includeTerminator = true)

还可以包含终止符,但默认情况下,它设置为false ..

更快的整体读取/上传(大文件),考虑增加<代码>缓冲区大小>代码>(<代码>源代码. Debug TufFistSosie<代码>设置为<代码> 2048代码>代码>,例如如下,

val file = new java.io.File("myFilename")
io.Source.fromFile(file, bufferSize = Source.DefaultBufSize * 2)

注意。有关进一步的讨论,请参见。

就像在Java中一样,使用CommonsIO库:

FileUtils.readFileToString(file, StandardCharsets.UTF_8)
此外,这里的许多答案都忘记了字符集。最好是明确地提供它,或者它会在某一天出现。

< P>模拟Ruby语法(并传达语义)打开和读取文件,考虑这个隐式类(Scala 2.10和Stand),

这样,

open("file.txt").read
还有一点:

在不将内容加载到内存的情况下读取文件的各种方法:

val bytes  : Iterator[Byte]            = file.bytes
val chars  : Iterator[Char]            = file.chars
val lines  : Iterator[String]          = file.lines
val source : scala.io.BufferedSource   = file.content 
您也可以为执行读/写操作的任何内容提供自己的编解码器(如果不提供,则假定为scala.io.codec.default):


您不需要解析每一行,然后再次连接它们

Source.fromFile(path)(Codec.UTF8).mkString
我更喜欢这样:

import scala.io.{BufferedSource, Codec, Source}
import scala.util.Try

def readFileUtf8(path: String): Try[String] = Try {
  val source: BufferedSource = Source.fromFile(path)(Codec.UTF8)
  val content = source.mkString
  source.close()
  content
}
爪哇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)
爪哇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”)
)更快。

import scala.io.source
import scala.io.source
object ReadLine{
def main(args:Array[String]){
if (args.length>0){
for (line <- Source.fromLine(args(0)).getLine())
println(line)
}
}
对象读线{ def main(参数:数组[字符串]){ 如果(参数长度>0){
如果你不介意第三方依赖,你应该考虑使用My。这使得读/写文件和文件系统工作非常方便:

// Make sure working directory exists and is empty
val wd = os.pwd/"out"/"splash"
os.remove.all(wd)
os.makeDir.all(wd)

// Read/write files
os.write(wd/"file.txt", "hello")
os.read(wd/"file.txt") ==> "hello"

// Perform filesystem operations
os.copy(wd/"file.txt", wd/"copied.txt")
os.list(wd) ==> Seq(wd/"copied.txt", wd/"file.txt")
使用、和许多其他有用/常用操作的单线帮助器

您可以使用

Source.fromFile(fileName).getLines().mkString
但是应该注意,getLines()会删除所有新行字符。 如果要保存格式,应使用

Source.fromFile(fileName).iter.mkString

说真的吗?你真的定期阅读多少文件在内存中存在实际问题?我处理过的绝大多数程序中的绝大多数文件都很小,可以很容易地放入内存。坦率地说,大数据文件是例外,如果你不这样做,你应该意识到这一点并相应地编程o正在读/写它们。我不同意。有许多情况涉及小文件,它们的大小在未来不会增长
import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Path}

val path = Path.of("file.txt")
Files.readString(path, StandardCharsets.UTF_8)
import scala.io.source
object ReadLine{
def main(args:Array[String]){
if (args.length>0){
for (line <- Source.fromLine(args(0)).getLine())
println(line)
}
}
// Make sure working directory exists and is empty
val wd = os.pwd/"out"/"splash"
os.remove.all(wd)
os.makeDir.all(wd)

// Read/write files
os.write(wd/"file.txt", "hello")
os.read(wd/"file.txt") ==> "hello"

// Perform filesystem operations
os.copy(wd/"file.txt", wd/"copied.txt")
os.list(wd) ==> Seq(wd/"copied.txt", wd/"file.txt")
Source.fromFile(fileName).getLines().mkString
Source.fromFile(fileName).iter.mkString