我按照Alvin Alexander的教程使用Loan Pattern
以下是我使用的代码 -
val year = 2016
val nationalData = {
val source = io.Source.fromFile(s"resources/Babynames/names/yob$year.txt")
// names is iterator of String, split() gives the array
//.toArray & toSeq is a slow process compare to .toSet // .toSeq gives Stream Closed error
val names = source.getLines().filter(_.nonEmpty).map(_.split(",")(0)).toSet
source.close()
names
// println(names.mkString(","))
}
println("Names " + nationalData)
val info = for (stateFile <- new java.io.File("resources/Babynames/namesbystate").list(); if stateFile.endsWith(".TXT")) yield {
val source = io.Source.fromFile("resources/Babynames/namesbystate/" + stateFile)
val names = source.getLines().filter(_.nonEmpty).map(_.split(",")).
filter(a => a(2).toInt == year).map(a => a(3)).toArray // .toSet
source.close()
(stateFile.take(2), names)
}
println(info(0)._2.size + " names from state "+ info(0)._1)
println(info(1)._2.size + " names from state "+ info(1)._1)
for ((state, sname) <- info) {
println("State: " +state + " Coverage of name in "+ year+" "+ sname.count(n => nationalData.contains(n)).toDouble / nationalData.size) // Set doesn't have length method
}
以上是我在上述代码中应用readTextFile
,readTextFileWithTry
来学习/试验上述代码中的Loan Pattern
def using[A <: { def close(): Unit }, B](resource: A)(f: A => B): B =
try {
f(resource)
} finally {
resource.close()
}
def readTextFile(filename: String): Option[List[String]] = {
try {
val lines = using(fromFile(filename)) { source =>
(for (line <- source.getLines) yield line).toList
}
Some(lines)
} catch {
case e: Exception => None
}
}
def readTextFileWithTry(filename: String): Try[List[String]] = {
Try {
val lines = using(fromFile(filename)) { source =>
(for (line <- source.getLines) yield line).toList
}
lines
}
}
val year = 2016
val data = readTextFile(s"resources/Babynames/names/yob$year.txt") match {
case Some(lines) =>
val n = lines.filter(_.nonEmpty).map(_.split(",")(0)).toSet
println(n)
case None => println("couldn't read file")
}
val data1 = readTextFileWithTry("resources/Babynames/namesbystate")
data1 match {
case Success(lines) => {
val info = for (stateFile <- data1; if stateFile.endsWith(".TXT")) yield {
val source = fromFile("resources/Babynames/namesbystate/" + stateFile)
val names = source.getLines().filter(_.nonEmpty).map(_.split(",")).
filter(a => a(2).toInt == year).map(a => a(3)).toArray // .toSet
(stateFile.take(2), names)
println(names)
}
}
但在第二种情况下readTextFileWithTry
,我收到以下错误 -
Failed, message is: java.io.FileNotFoundException: resources\Babynames\namesbystate (Access is denied)
我想失败的原因来自SO我的理解 -
I am trying to open the same file on each iteration of the for loop
除此之外,我对我的使用方式几乎没有关注 -
readTextFileWithTry
或Option[A]
/ Set
或Scala Collection的Map
的返回类型,以便稍后应用更高阶函数。但无法成功。不确定这是一个好习惯。Success
情况下使用高阶函数,因为有多个操作,在Success
情况下代码块会变大?我无法使用Success
案例之外的任何字段。有人可以帮我理解吗?
答案 0 :(得分:0)
我认为你的问题与&#34; 无关。我试图在for循环的每次迭代中打开相同的文件&#34;它实际上与accepted answer
中的相同不幸的是,您没有提供堆栈跟踪,因此不清楚这是发生了哪一行。我猜这个下降的电话是
val data1 = readTextFileWithTry("resources/Babynames/namesbystate")
查看您的第一个代码示例:
val info = for (stateFile <- new java.io.File("resources/Babynames/namesbystate").list(); if stateFile.endsWith(".TXT")) yield {
看起来路径"resources/Babynames/namesbystate"
指向目录。但在第二个示例中,您尝试将其作为文件读取,这就是错误的原因。这是因为您的readTextFileWithTry
不是java.io.File.list
来电的有效替代品。并且File.list
不需要包装器,因为它不使用任何中间可关闭/一次性实体。
P.S。使用File.list(FilenameFilter filter)
代替if stateFile.endsWith(".TXT"))