我有一个包含10行的文件 - 我想检索它,然后用换行符(“\ n”)分隔符拆分它们。
这就是我做的事情
val data = io.Source.fromFile("file.txt").toString;
但是当我尝试在换行符上拆分文件时,这会导致错误。
然后我尝试了
val data = io.Source.fromFile("file.txt").mkString;
它有效。
到底是什么?有人能告诉我这两种方法有什么区别吗?
答案 0 :(得分:34)
让我们来看看这些类型,好吗?
scala> import scala.io._
import scala.io._
scala> val foo = Source.fromFile("foo.txt")
foo: scala.io.BufferedSource = non-empty iterator
scala>
现在,您已将文件foo.txt
读入的变量是迭代器。如果对其执行toString()
调用,则不会返回文件的内容,而是返回您创建的迭代器的String表示形式。 OTOH,mkString()
读取迭代器(即迭代它)并根据从中读取的值构造一个长String。
有关详细信息,请查看此控制台会话:
scala> foo.toString
res4: java.lang.String = non-empty iterator
scala> res4.foreach(print)
non-empty iterator
scala> foo.mkString
res6: String =
"foo
bar
baz
quux
dooo
"
scala>
答案 1 :(得分:24)
toString方法应该返回对象的字符串表示形式。它经常被覆盖以提供有意义的表示。 mkString方法是在集合上定义的,是一种将集合的元素与提供的字符串连接起来的方法。例如,尝试类似:
val a = List("a", "b", "c")
println(a.mkString(" : "))
你会得到“a:b:c”作为输出。 mkString方法通过使用您提供的字符串连接集合的元素,从集合中创建了一个字符串。在您发布的特定情况下,mkString调用将BufferedSource迭代器返回的元素与空字符串连接起来(这是因为您调用了没有参数的mkString)。这导致简单地将集合中的所有字符串(由BufferedSource迭代器产生)连接在一起。
另一方面,在这里调用toString并没有多大意义,因为你得到的(当你没有得到错误时)是BufferedSource迭代器的字符串表示形式;它只是告诉你迭代器是非空的。
答案 2 :(得分:2)
他们在不同的班级中有不同的方法。在这种情况下,mkString是特征GenTraversableOnce中的一种方法。 toString在Any上定义(并且经常被覆盖)。
最简单的方法(或至少我通常使用的方式)找出这个是使用http://www.scala-lang.org/api/current/index.html处的文档。从您的变量类型开始:
val data = io.Source.fromFile("file.txt")
的类型为
scala.io.BufferedSource
转到BufferedSource的文档,然后查找mkString。在mkString的文档中(点击左下方的向下箭头),您会看到它来自
Definition Classes TraversableOnce → GenTraversableOnce
用toString做同样的事情。
答案 3 :(得分:1)
我认为问题是要了解Source类正在做什么。从您的代码中可以看出,您希望Source.fromFile检索文件的内容,而它实际上是指向文件的开头。
这在使用I / O操作时很常见,您必须打开与资源的“连接”(在这种情况下是与文件系统的连接),多次读/写然后关闭该“连接”。在您的示例中,您打开了与文件的连接,并且必须每行读取文件的内容,直到结束。认为当你读到你正在内存中加载信息时,所以在大多数情况下(mkString将要做的)将整个文件加载到内存中并不是一个好主意。
另一方面,mkString用于迭代集合的所有元素,因此在这种情况下,读取文件并在内存中加载Array [String]。要小心,因为如果文件太大,您的代码将失败,通常在使用I / O时,您应该使用缓冲区来读取某些内容,然后处理/保存该内容,然后加载更多内容(在同一缓冲区中),避免出现问题有记忆。例如,阅读5行 - >解析 - >保存已解析的行 - >阅读接下来的5行 - >等
您还可以理解“toString”没有检索到任何内容......只是告诉您“您可以读取行,文件不为空”。