问题
I'm using a recursive function to traverse files under a root directory. I only want to extract *.txt
files, but I don't want to exclude directories. Right now my code looks like this:
val stream = Files.newDirectoryStream(head, "*.txt")
But by doing this, it will not match any directories, and the iterator()
gets returned is False
. I'm using a Mac, so the noise file that I don't want to include is .DS_STORE
. How can I let newDirectoryStream
get directories and files that are *.txt
? Is there a way?
回答1:
You really should use FileVisistor
, it makes the code as simple as this:
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file._
import scala.collection.mutable.ArrayBuffer
val files = ArrayBuffer.empty[Path]
val root = Paths.get("/path/to/your/directory")
Files.walkFileTree(root, new SimpleFileVisitor[Path] {
override def visitFile(file: Path, attrs: BasicFileAttributes) = {
if (file.getFileName.toString.endsWith(".txt")) {
files += file
}
FileVisitResult.CONTINUE
}
})
files.foreach(println)
回答2:
Not sure if nio is a requirement. If not this is fairly simple and seems to do the job. And has no mutable collections :)
import java.io.File
def collectFiles(dir: File) = {
def collectFilesHelper(dir: File, soFar: List[String]): List[String] = {
dir.listFiles.foldLeft(soFar) { (acc: List[String], f: File) =>
if (f.isDirectory)
collectFilesHelper(f, acc)
else if (f.getName().endsWith(".txt"))
f.getCanonicalPath() :: acc
else acc
}
}
collectFilesHelper(dir, List[String]())
}
回答3:
Well, I didn't actually use FileVisitor
, but it should be nice to use it. I used recursion and keep two lists: one is the raw file list to track down directories, the other list is used to store actual *.txt
files:
@tailrec
def recursiveTraverse(filePaths: ListBuffer[Path], resultFiles: ListBuffer[Path]): ListBuffer[Path] = {
if (filePaths.isEmpty) resultFiles
else {
val head = filePaths.head
val tail = filePaths.tail
if (Files.isDirectory(head)) {
val stream: Try[DirectoryStream[Path]] = Try(Files.newDirectoryStream(head))
stream match {
case Success(st) =>
val iterator = st.iterator()
while (iterator.hasNext) {
tail += iterator.next()
}
case Failure(ex) => println(s"The file path is incorrect: ${ex.getMessage}")
}
stream.map(ds => ds.close())
recursiveTraverse(tail, resultFiles)
}
else{
if (head.toString.contains(".txt")) {
recursiveTraverse(tail, resultFiles += head)
}else{
recursiveTraverse(tail, resultFiles)
}
}
}
}
However, this is not the best solution, but is the easiest for my specific problem. Please show a maybe much shorter FileVisitor
code, if you want to do it :)
来源:https://stackoverflow.com/questions/25249424/java-globbing-pattern-to-match-directory-and-file