在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()
Daniel C. So.. 420
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"
"slurp"一直是在Perl中读取整个文件多年的名称.Perl比C语言系列具有更为内在和非正式的命名传统,有些人可能会觉得这些语言令人反感,但在这种情况下我觉得它很合适:对于丑陋的练习来说,这是一个丑陋的词.当你啜饮()时,你知道你正在做一些顽皮的事情,因为你只需输入它. (48认同)
我已经来晚了,但是我讨厌那些不知道他们可以做"io.File("/ etc/passwd")的人."在行李箱里啜饮. (45认同)
@extempore如果你真的觉得我没办法,我真的很抱歉.我非常感谢您对Scala语言的支持,并且每次您亲自调查我提出的问题时,建议解决我遇到的问题,或者向我解释一些问题.那么,我将借此机会感谢您将scala.io转变为体面和值得的东西.从现在开始,我会更加直言不讳,但我仍然讨厌这个名字,对不起. (27认同)
@extempore:你无法阻止人们反感.这就是它的方式.有些人不喜欢你所做的每一个选择都不应该打扰你.这只是生活,你不能取悦每个人:) (26认同)
File.read()将是一个更好的名称,并与Ruby和Python一致. (15认同)
请注意,只需调用fromFile.getLines即可实例化Source实例但不关闭它.这意味着Scala运行时可能会保留对文件系统中文件的锁定,从而防止它被打开以进行写入,重命名,删除等,只要Scala Source insance持有锁定即可.以下将读取文件并关闭文件.def linesFrom(fileName:String):List [String] = {val source = scala.io.Source.fromFile(fileName)val text = source.getLines source.close()text} (13认同)
我讨厌Scala 2.8有一个名为"`slurp`"的方法,但似乎我仍然坚持使用它. (6认同)
我不想要更多的声音谢谢,我希望你和其他所有人能够压抑这种压倒性的厌恶,而只是提出建议.另外要记住,我是唯一一个在大多数标准库和大部分编译器上工作的人,而且只有这么多小时. (6认同)
我会就这个名字进行谈判,但由于你"完全厌恶",我会尽力保持原样.谢谢你特别的吃力不讨好. (5认同)
赞成使用`slurp` - 现在永远不会忘记它. (5认同)
顺便说一句,裸的`mkString`(没有`getLines`)在2.11中得到修复. (2认同)
Daniel Spiew.. 56
只是为了扩展Daniel的解决方案,您可以通过将以下导入插入到需要文件操作的任何文件中来极大地缩短范围:
import scala.io.Source._
有了这个,你现在可以做到:
val lines = fromFile("file.txt").getLines
我会警惕将整个文件读成单个文件String
.这是一个非常糟糕的习惯,会比你想象的更快,更难咬你.该getLines
方法返回type的值Iterator[String]
.它实际上是一个放入文件的懒惰光标,允许您只检查所需的数据而不会有内存过剩的风险.
哦,并回答你的隐含问题Source
:是的,它是规范的I/O库.大多数代码java.io
由于其较低级别的接口和与现有框架的更好兼容性而最终使用,但是任何有选择的代码都应该使用Source
,特别是对于简单的文件操作.
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"
只是为了扩展Daniel的解决方案,您可以通过将以下导入插入到需要文件操作的任何文件中来极大地缩短范围:
import scala.io.Source._
有了这个,你现在可以做到:
val lines = fromFile("file.txt").getLines
我会警惕将整个文件读成单个文件String
.这是一个非常糟糕的习惯,会比你想象的更快,更难咬你.该getLines
方法返回type的值Iterator[String]
.它实际上是一个放入文件的懒惰光标,允许您只检查所需的数据而不会有内存过剩的风险.
哦,并回答你的隐含问题Source
:是的,它是规范的I/O库.大多数代码java.io
由于其较低级别的接口和与现有框架的更好兼容性而最终使用,但是任何有选择的代码都应该使用Source
,特别是对于简单的文件操作.
// for file with utf-8 encoding val lines = scala.io.Source.fromFile("file.txt", "utf-8").getLines.mkString
(编辑:这在scala 2.9中不起作用,也许不是2.8)
使用trunk:
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.
另一个有趣的解决方案是使用scalax.这是一个很好评论的代码示例,它使用ManagedResource打开一个日志文件,用scalax助手打开一个文件:http://pastie.org/pastes/420714
在scala.io.Source上使用getLines()会丢弃用于行终止符的字符(\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) }
就像在Java中一样,使用CommonsIO库:
FileUtils.readFileToString(file, StandardCharsets.UTF_8)
此外,许多答案在这里忘记了Charset.最好总是明确地提供它,否则它会在一天内发布.
还有一个: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")