我最近学会了如何使用Scala的原生Try
类型来处理错误。 Try
的一个好处是,我能够使用for -reherehence并默默地忽略错误。
然而,这对Java的NIO包(我真的想要使用)来说只是一个小问题。
val p = Paths.get("Some File Path")
for {
stream <- Try(Files.newDirectoryStream(p))
file:Path <- stream.iterator()
} yield file.getFileName
这本来是完美的。我打算从目录中获取所有文件名,使用DirectoryStream[Path]
是最好的方法,因为它可以很好地扩展。 NIO页面说DirectoryStream
有一个返回迭代器的iterator()
方法。对于Java的for循环,它已经足够了,可以这样使用:
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path file: stream) {
System.out.println(file.getFileName());
}
}
然而,Scala不接受这一点。我受到了错误的欢迎:
[error] /.../DAL.scala:42: value filter is not a member of java.util.Iterator[java.nio.file.Path]
[error] file:Path <- stream.iterator
我尝试使用JavaConverters
,它显示它处理Java Iterator
类型:scala.collection.Iterator <=> java.util.Iterator
,但当我尝试以这种方式调用它时:stream.iterator().asScala
,方法无法访问。
我该怎么办?如何在使用NIO包的同时编写好的Scala代码?
答案 0 :(得分:2)
我实际上并没有完全理解filter
正在被调用,但请注意stream.iterator()
会返回Iterator[Path]
,而不是Path
,即使我的IDE认为它确实如此,可能是因为他认为他可以将map
应用于它,但实际上这是在编译器确认的java.util.Iterator[java.nio.file.Path]
上没有定义的方法:
scala> for {
| stream <- Try(Files.newDirectoryStream(p))
| file <- stream.iterator()
| } yield file
<console>:13: error: value map is not a member of java.util.Iterator[java.nio.file.Path]
file <- stream.iterator()
理解能力转化为:
Try(Files.newDirectoryStream(p)).flatMap(stream => stream.iterator().map(...))
未定义第二个map
的位置。一个解决方案可以在这个SO question中找到,但我不能告诉你如何在这里使用迭代器进行理解,因为在java迭代器中无法映射,我不确定你是否可以将它转换为理解。
编辑:
我设法找到了更多关于这个问题的信息,我试着理解这个问题:
for {
stream <- Try(Files.newDirectoryStream(p))
file <- stream.iterator().toIterator
} yield file
这不能编译,因为:
found : Iterator[java.nio.file.Path]
required: scala.util.Try[?]
file <- stream.iterator().toIterator
它转换为:
Try(Files.newDirectoryStream(p)).flatMap(stream => stream.iterator().map(...))
但是flatMap
实际上期望Try
回来,实际上这有效:
Try(Files.newDirectoryStream(p)).flatMap(stream => Try(stream.iterator().map(...)))
^
我想出了什么:
import java.nio.file.{Paths, Files}
import util.Try
import scala.collection.JavaConversions._
Try(Files.newDirectoryStream(p))
.map(stream =>
stream
.iterator()
.toIterator
.toList
.map(path => path.getFileName.toString)
).getOrElse(List())
返回一个List[String]
,不幸的是,这远不像你的理解那样漂亮,也许其他人有更好的主意。
答案 1 :(得分:0)
我非常喜欢Ende Neu所写的内容,并且很难在Scala中使用NIO。我想保留Java的Stream带来的效率,所以我决定改写这个函数。它仍然使用Try
,我只需处理Success
和Failure
个案例:)
它并不像我希望的那么顺利,如果没有Java 7的优秀try-with-resource
功能,我必须自己关闭流(这很糟糕......),但这样做了。
def readFileNames(filePath: String):Option[List[Path]] = {
val p = Paths.get(filePath)
val stream: Try[DirectoryStream[Path]] = Try(Files.newDirectoryStream(p))
val listOfFiles = List[Path]()
stream match {
case Success(st) =>
val iterator = st.iterator()
while (iterator.hasNext) {
listOfFiles :+ iterator.next()
}
case Failure(ex) => println(s"The file path is incorrect: ${ex.getMessage}")
}
stream.map(ds => ds.close())
if(listOfFiles.isEmpty) None else Some(listOfFiles)
}