在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。
为了更快的整体读取/上传(大)文件,请考虑增加bufferSize
( Source.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.Source
从getLines
方法返回一个Iterator[String]
,这非常有用和简洁。
使用底层的Java IO实用程序将File
, Reader
或InputStream
转换为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,它会返回所有行