在Scala中读取整个文件?

在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() 
 val lines = scala.io.Source.fromFile("file.txt").mkString 

顺便说一句,“ scala. ”并不是真的有必要,因为它总是在范围内,当然,你可以完全或部分地导入io的内容,并且避免必须添加“io”。 太。

上面的文件打开,但是。 为了避免问题,你应该像这样closures它:

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

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

 source.getLines mkString "\n" 

为了扩展Daniel的解决scheme,可以通过将以下导入插入任何需要文件操作的文件中,从而大大缩短事情的执行时间:

 import scala.io.Source._ 

有了这个,你现在可以做到:

 val lines = fromFile("file.txt").getLines 

我会小心阅读整个文件到一个单一的String 。 这是一个非常不好的习惯,会比你想象的更快,更难咬你。 getLines方法返回一个types为Iterator[String] 。 它实际上是一个懒惰的光标到文件中,允许你检查你所需要的数据,而不会冒着内存过剩的风险。

哦,并回答你的隐含的问题Source :是的,这是规范的I / O库。 大多数代码由于其底层接口和现有框架的兼容性而最终使用java.io ,但任何有select的代码都应该使用Source ,尤其是对于简单的文件操作。

 // for file with utf-8 encoding val lines = scala.io.Source.fromFile("file.txt", "utf-8").getLines.mkString 

(编辑:这不适用于斯卡拉2.9,也许不是2.8)

使用主干:

 scala> io.File("/etc/passwd").slurp res0: String = ## # User Database # ... etc 
 import java.nio.charset.StandardCharsets._ import java.nio.file.{Files, Paths} new String(Files.readAllBytes(Paths.get("file.txt")), UTF_8) 

控制字符编码,没有资源清理。 此外,还进行了优化,因为Files.readAllBytes分配一个与文件大小相匹配的字节数组。

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

另一个有趣的解决scheme是使用scalax。 下面是一些很好的评论代码的例子,它使用ManagedResource打开一个日志文件,用scalax助手打开一个文件: http ://pastie.org/pastes/420714

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

下面应该保留它的字符为字符,并不会做过多的string连接(性能问题):

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

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

 FileUtils.readFileToString(file, StandardCharsets.UTF_8) 

此外,这里的许多答案忘记了Charset。 总是明确地提供它,或者有一天会被打开。

正如less数人提到scala.io.Source最好能够避免由于连接泄漏。

可能scalax和像commons-io这样的纯java库是最好的select,直到新的孵化器项目(即scala-io)被合并。

你也可以使用Scala io的Path来读取和处理文件。

 import scalax.file.Path 

现在你可以使用这个文件path:

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

您也可以包含结束符,但默认情况下它被设置为false。

为了更快的整体读取/上传(大)文件,请考虑增加bufferSizeSource.DefaultBufSize设置为2048 )的大小,例如如下所示,

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

注意Source.scala 。 有关进一步的讨论,请参阅Scala快速文本文件读取并上传到内存 。

为了模拟打开和读取文件的Ruby语法(并传达语义),考虑这个隐式类(Scala 2.10和更高版本),

 import java.io.File def open(filename: String) = new File(filename) implicit class RichFile(val file: File) extends AnyVal { def read = io.Source.fromFile(file).getLines.mkString("\n") } 

通过这种方式,

 open("file.txt").read 

还有一个: https : //github.com/pathikrit/better-files#streams-and-codecs

不加载内容到内存中的各种方法,

 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):

 val content: String = file.contentAsString // default codec // custom codec: import scala.io.Codec file.contentAsString(Codec.ISO8859) //or import scala.io.Codec.string2codec file.write("hello world")(codec = "US-ASCII") 

显而易见的问题是“你为什么要阅读整个文件?” 这显然不是一个可扩展的解决scheme,如果你的文件变得非常大。 scala.io.SourcegetLines方法返回一个Iterator[String] ,这非常有用和简洁。

使用底层的Java IO实用程序将FileReaderInputStream转换为String的隐式转换并不是什么InputStream 。 我认为缺乏可扩展性意味着他们是正确的,不把它添加到标准的API。

打印每一行,如使用Java BufferedReader读取行,并打印它:

 scala.io.Source.fromFile("test.txt" ).foreach{ print } 

当量:

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

你不需要parsing每一行,然后再连接它们…

 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 } 
 import scala.io.source object ReadLine{ def main(args:Array[String]){ if (args.length>0){ for (line <- Source.fromLine(args(0)).getLine()) println(line) } } 

在参数你可以给文件path,它会返回所有行