2009-08-16 49 views
277

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

最好我可以想出的是:

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

或我应该使用的Java's god-awful idioms酮,(不使用外部库,最好的)似乎是:

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() 
+12

Java的心不是那么糟糕,如果你知道正确的工具。 import org.apache.commons.io.FileUtils; FileUtils.readFileToString(new File(“file.txt”,“UTF-8”) – smartnut007 2011-06-18 00:01:04

+19

这个评论忽略了语言设计的重点,任何语言都可以使用简单的库函数来完成你想要执行的操作,作为其函数调用语法 给定一个无限且100%记忆的库,所有程序都将通过一个函数调用来实现 编程语言是好的,因为它需要更少的预制组件来实现 – 2014-02-09 05:45:04

回答

378
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" 
+0

啊,肯定比betterLeft(_ + _)更好 – 2009-08-16 15:06:55

+41

我对派对来说太迟了,但我讨厌别人不知道他们可以做“io.File(”/ etc/passwd “).slurp”in trunk。 – extempore 2009-08-26 03:48:13

+6

我讨厌Scala 2.8有一个名为“'slurp'”的方法,但似乎我卡在了w无论如何。 – 2009-08-26 13:34:18

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

将“getLines”添加到原始答案将删除所有换行符。应该是“Source.fromFile(”file.txt“,”utf-8“)。mkString”。 – Joe23 2010-12-16 10:54:23

+9

另请参阅我在Daniel C. Sobral的回答中的评论 - 此用法不会关闭Source实例,因此Scala可能会保留该文件的锁定。 – djb 2011-08-01 02:51:39

1

最明显的问题是这显然不是一个可扩展的解决方案,如果你的文件变得非常大。 scala.io.SourcegetLines方法给你回Iterator[String],这是非常有用和简洁。

这不是太大的工作拿出使用底层Java IO公用事业一个File,一个ReaderInputStreamString转换的隐式转换。我认为可扩展性的缺乏意味着他们是正确的,不会将其添加到标准API中。

+11

认真吗?你经常读到多少个文件,这些文件在内存中存在真正的问题?绝大多数我曾经处理过的程序中的绝大多数文件都足够小,以适应内存。坦率地说,大数据文件是例外情况,如果您要阅读/编写大数据文件,您应该认识到并编写相应的程序。 – Christopher 2009-08-17 15:24:01

+8

oxbow_lakes,我不同意。很多情况下,小型文件的大小在未来不会增长。 – 2009-08-18 16:37:32

+4

我同意他们是例外 - 但我认为这就是为什么读取整个文件到内存不在JDK或Scala SDK中。这是一个3行实用程序方法供您自己编写:克服它 – 2009-08-18 17:16:20

50

只是对丹尼尔的解决方案扩展,可以极大地插入以下导入到任何文件,该文件要求文件操作缩短东西:

import scala.io.Source._ 

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

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

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

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

+0

好的。我对Source的负面印象有一个故事:我曾经处于与现在不同的情况,那里有一个非常大的文件,不适合记忆。使用Source导致程序崩溃;原来它试图一次读完所有的东西。 – 2009-08-18 16:38:57

+6

源不应该将整个文件读入内存。如果你在getLines之后使用toList,或者其他一些会产生集合的方法,那么你将所有东西都放到内存中。现在,Source是一个* hack *,意在完成工作,而不是经过深思熟虑的库。它将在Scala 2.8中得到改进,但Scala社区绝对有机会积极地定义一个好的I/O API。 – 2009-08-18 21:08:27

6

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

另一个有趣的解决方案是使用scalax。下面是在使用ManagedResource为打开与scalax助手一个文件打开一个日志文件中的一些很好的注释代码示例:http://pastie.org/pastes/420714

+1

+ +1提及scalax – 2009-08-20 20:15:37

24

(编辑:这并不在斯卡拉2.9工作,也许不是2.8或者)

使用后备箱:

scala> io.File("/etc/passwd").slurp 
res0: String = 
## 
# User Database 
# 
... etc 
+13

“'slurp'”?我们真的放弃了明显,直观的名字吗? “slurp”的问题在于,事后对于以英语作为第一语言的人来说可能是有意义的,至少,但你永远不会想到它开始! – 2009-08-26 13:32:23

+4

只是偶然发现了这个问题/答案。 'File'不再在2.8.0中,不是吗? – huynhjl 2010-02-21 05:38:11

+3

您仍然可以从scala.tools.nsc.io.File中偷取它,但我认为该位置可能会在未来发生变化,因此请自担风险。 ;-)哦,让我来说说我多么讨厌“slurp”这个名字。 – Steve 2010-08-03 15:01:38

2

作为少数人提到scala.io.Source是最好避免由于连接泄漏。

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

5

使用getLines()上使用了哪些字符,行终结scala.io.Source丢弃(\ 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) 
} 
0

打印每行,如采用Java的BufferedReader读ervery线,并打印:

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

相当于:

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

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

import scalax.file.Path 

现在你可以使用这个获取文件的路径: -

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

您还可以终止,但默认情况下它被设置为false ..

2

对于更快的整体读取/上传(大)文件,考虑增大尺寸bufferSizeSource.DefaultBufSize设为2048),例如如下,

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

注意Source.scala。有关进一步的讨论,请参阅Scala fast text file read and upload to memory

4

就像在Java中,使用CommonsIO库:

FileUtils.readFileToString(file, StandardCharsets.UTF_8) 

而且,很多答案忘在这里字符集。最好总是明确地提供它,否则它会在一天内出现。

2

为了模拟打开和读取文件的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 
2

一个更: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。默认值,如果不提供一个):

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") 
0

你并不需要解析每一个线,然后再次将它们连接起来......

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 
} 
10
import java.nio.charset.StandardCharsets._ 
import java.nio.file.{Files, Paths} 

new String(Files.readAllBytes(Paths.get("file.txt")), UTF_8) 

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

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

在争论你可以给文件的路径,它将返回所有行

+0

这是什么提供其他答案没有? – jwvh 2017-07-23 21:58:57

+0

还没有看到其他答案......只是以为我可以在这里发布这么贴......希望这不会伤害任何人:) – Apurw 2017-07-24 14:52:33

+0

你真的应该阅读它们。大多数信息丰富。即使是8岁的人也有相关的信息。 – jwvh 2017-07-24 16:37:19