Scala의 하위 디렉토리에있는 모든 파일을 어떻게 나열합니까?
디렉토리에있는 파일을 재귀 적으로 나열하는 좋은 "scala-esque"(내가 기능적이라는 의미) 방법이 있습니까? 특정 패턴을 일치시키는 것은 어떻습니까?
예를 들어 재귀 적으로 모든 파일이 일치 "a*.foo"
에서 c:\temp
.
Scala 코드는 일반적으로 디렉토리 읽기를 포함하여 I / O를 처리하기 위해 Java 클래스를 사용합니다. 따라서 다음과 같이해야합니다.
import java.io.File
def recursiveListFiles(f: File): Array[File] = {
val these = f.listFiles
these ++ these.filter(_.isDirectory).flatMap(recursiveListFiles)
}
모든 파일을 수집 한 다음 정규식을 사용하여 필터링 할 수 있습니다.
myBigFileArray.filter(f => """.*\.html$""".r.findFirstIn(f.getName).isDefined)
또는 정규식을 재귀 검색에 통합 할 수 있습니다.
import scala.util.matching.Regex
def recursiveListFiles(f: File, r: Regex): Array[File] = {
val these = f.listFiles
val good = these.filter(f => r.findFirstIn(f.getName).isDefined)
good ++ these.filter(_.isDirectory).flatMap(recursiveListFiles(_,r))
}
무한 파일 시스템을 반복 할 수 있기 때문에 Streams 솔루션을 선호합니다 (스트림은 게으른 평가 컬렉션입니다)
import scala.collection.JavaConversions._
def getFileTree(f: File): Stream[File] =
f #:: (if (f.isDirectory) f.listFiles().toStream.flatMap(getFileTree)
else Stream.empty)
검색 예
getFileTree(new File("c:\\main_dir")).filter(_.getName.endsWith(".scala")).foreach(println)
for (file <- new File("c:\\").listFiles) { processFile(file) }
http://langref.org/scala+java/files
Java 1.7부터는 모두 java.nio를 사용해야합니다. 네이티브에 가까운 성능을 제공하며 (java.io는 매우 느림) 유용한 도우미가 있습니다.
그러나 Java 1.8은 정확히 원하는 것을 소개합니다.
import java.nio.file.{FileSystems, Files}
import scala.collection.JavaConverters._
val dir = FileSystems.getDefault.getPath("/some/path/here")
Files.walk(dir).iterator().asScala.filter(Files.isRegularFile(_)).foreach(println)
또한 파일 일치를 요청했습니다. 시도 java.nio.file.Files.find
하고 또한java.nio.file.Files.newDirectoryStream
http://docs.oracle.com/javase/tutorial/essential/io/walk.html에서 문서를 참조하십시오.
Scala는 다중 패러다임 언어입니다. 디렉토리를 반복하는 좋은 "scala-esque"방법은 기존 코드를 재사용하는 것입니다!
commons-io를 사용하여 디렉토리를 반복하는 완벽하게 스칼라와 같은 방법을 고려할 것 입니다. 암시 적 변환을 사용하여 더 쉽게 만들 수 있습니다. 처럼
import org.apache.commons.io.filefilter.IOFileFilter
implicit def newIOFileFilter (filter: File=>Boolean) = new IOFileFilter {
def accept (file: File) = filter (file)
def accept (dir: File, name: String) = filter (new java.io.File (dir, name))
}
나는 yura의 스트림 솔루션을 좋아하지만 숨겨진 디렉토리로 재귀합니다. listFiles
디렉토리가 아닌 경우 null을 반환 한다는 사실을 활용하여 단순화 할 수도 있습니다 .
def tree(root: File, skipHidden: Boolean = false): Stream[File] =
if (!root.exists || (skipHidden && root.isHidden)) Stream.empty
else root #:: (
root.listFiles match {
case null => Stream.empty
case files => files.toStream.flatMap(tree(_, skipHidden))
})
이제 파일을 나열 할 수 있습니다.
tree(new File(".")).filter(f => f.isFile && f.getName.endsWith(".html")).foreach(println)
또는 나중에 처리하기 위해 전체 스트림을 실현
tree(new File("dir"), true).toArray
Apache Commons Io의 FileUtils 는 한 줄에 맞으며 매우 읽기 쉽습니다 .
import scala.collection.JavaConversions._ // important for 'foreach'
import org.apache.commons.io.FileUtils
FileUtils.listFiles(new File("c:\temp"), Array("foo"), true).foreach{ f =>
}
아무도 아직 언급하지 않았습니다 https://github.com/pathikrit/better-files
val dir = "src"/"test"
val matches: Iterator[File] = dir.glob("**/*.{java,scala}")
// above code is equivalent to:
dir.listRecursively.filter(f => f.extension ==
Some(".java") || f.extension == Some(".scala"))
scala.tools.nsc.io 살펴보기
Directory 클래스에 대한 자세한 목록 기능을 포함하여 매우 유용한 유틸리티가 있습니다.
내가 올바르게 기억한다면 이것은 retronym에 의해 강조되었고 (아마도 기고) io가 표준 라이브러리에서 새롭고 더 완전한 구현을 얻기 전에 임시 방편으로 간주되었습니다.
다음은 @DuncanMcGregor의 스트림 솔루션과 @ Rick-777의 필터를 혼합 한 것입니다.
def tree( root: File, descendCheck: File => Boolean = { _ => true } ): Stream[File] = {
require(root != null)
def directoryEntries(f: File) = for {
direntries <- Option(f.list).toStream
d <- direntries
} yield new File(f, d)
val shouldDescend = root.isDirectory && descendCheck(root)
( root.exists, shouldDescend ) match {
case ( false, _) => Stream.Empty
case ( true, true ) => root #:: ( directoryEntries(root) flatMap { tree( _, descendCheck ) } )
case ( true, false) => Stream( root )
}
}
def treeIgnoringHiddenFilesAndDirectories( root: File ) = tree( root, { !_.isHidden } ) filter { !_.isHidden }
이것은 당신에게 (잠재적으로 크고 매우 느린) List [File] 대신 Stream [File]을 제공하는 한편, 당신은 reduceCheck () 함수로 어떤 종류의 디렉토리로 재귀 할 것인지 결정할 수있게 해줍니다.
어때
def allFiles(path:File):List[File]=
{
val parts=path.listFiles.toList.partition(_.isDirectory)
parts._2 ::: parts._1.flatMap(allFiles)
}
Scala has library 'scala.reflect.io' which considered experimental but does the work
import scala.reflect.io.Path
Path(path) walkFilter { p =>
p.isDirectory || """a*.foo""".r.findFirstIn(p.name).isDefined
}
I personally like the elegancy and simplicity of @Rex Kerr's proposed solution. But here is what a tail recursive version might look like:
def listFiles(file: File): List[File] = {
@tailrec
def listFiles(files: List[File], result: List[File]): List[File] = files match {
case Nil => result
case head :: tail if head.isDirectory =>
listFiles(Option(head.listFiles).map(_.toList ::: tail).getOrElse(tail), result)
case head :: tail if head.isFile =>
listFiles(tail, head :: result)
}
listFiles(List(file), Nil)
}
Here's a similar solution to Rex Kerr's, but incorporating a file filter:
import java.io.File
def findFiles(fileFilter: (File) => Boolean = (f) => true)(f: File): List[File] = {
val ss = f.list()
val list = if (ss == null) {
Nil
} else {
ss.toList.sorted
}
val visible = list.filter(_.charAt(0) != '.')
val these = visible.map(new File(f, _))
these.filter(fileFilter) ++ these.filter(_.isDirectory).flatMap(findFiles(fileFilter))
}
The method returns a List[File], which is slightly more convenient than Array[File]. It also ignores all directories that are hidden (ie. beginning with '.').
It's partially applied using a file filter of your choosing, for example:
val srcDir = new File( ... )
val htmlFiles = findFiles( _.getName endsWith ".html" )( srcDir )
The simplest Scala-only solution (if you don't mind requiring the Scala compiler library):
val path = scala.reflect.io.Path(dir)
scala.tools.nsc.io.Path.onlyFiles(path.walk).foreach(println)
Otherwise, @Renaud's solution is short and sweet (if you don't mind pulling in Apache Commons FileUtils):
import scala.collection.JavaConversions._ // enables foreach
import org.apache.commons.io.FileUtils
FileUtils.listFiles(dir, null, true).foreach(println)
Where dir
is a java.io.File:
new File("path/to/dir")
It seems nobody mentions the scala-io
library from scala-incubrator...
import scalax.file.Path
Path.fromString("c:\temp") ** "a*.foo"
Or with implicit
import scalax.file.ImplicitConversions.string2path
"c:\temp" ** "a*.foo"
Or if you want implicit
explicitly...
import scalax.file.Path
import scalax.file.ImplicitConversions.string2path
val dir: Path = "c:\temp"
dir ** "a*.foo"
Documentation is available here: http://jesseeichar.github.io/scala-io-doc/0.4.3/index.html#!/file/glob_based_path_sets
This incantation works for me:
def findFiles(dir: File, criterion: (File) => Boolean): Seq[File] = {
if (dir.isFile) Seq()
else {
val (files, dirs) = dir.listFiles.partition(_.isFile)
files.filter(criterion) ++ dirs.toSeq.map(findFiles(_, criterion)).foldLeft(Seq[File]())(_ ++ _)
}
}
You can use tail recursion for it:
object DirectoryTraversal {
import java.io._
def main(args: Array[String]) {
val dir = new File("C:/Windows")
val files = scan(dir)
val out = new PrintWriter(new File("out.txt"))
files foreach { file =>
out.println(file)
}
out.flush()
out.close()
}
def scan(file: File): List[File] = {
@scala.annotation.tailrec
def sc(acc: List[File], files: List[File]): List[File] = {
files match {
case Nil => acc
case x :: xs => {
x.isDirectory match {
case false => sc(x :: acc, xs)
case true => sc(acc, xs ::: x.listFiles.toList)
}
}
}
}
sc(List(), List(file))
}
}
Why are you using Java's File instead of Scala's AbstractFile?
With Scala's AbstractFile, the iterator support allows writing a more concise version of James Moore's solution:
import scala.reflect.io.AbstractFile
def tree(root: AbstractFile, descendCheck: AbstractFile => Boolean = {_=>true}): Stream[AbstractFile] =
if (root == null || !root.exists) Stream.empty
else
(root.exists, root.isDirectory && descendCheck(root)) match {
case (false, _) => Stream.empty
case (true, true) => root #:: root.iterator.flatMap { tree(_, descendCheck) }.toStream
case (true, false) => Stream(root)
}
참고URL : https://stackoverflow.com/questions/2637643/how-do-i-list-all-files-in-a-subdirectory-in-scala
'Programing' 카테고리의 다른 글
Android Studio Gradle 동기화를 수동으로 실행하는 방법은 무엇입니까? (0) | 2020.09.06 |
---|---|
i ++가 스레드로부터 안전하지 않다고 들었습니다. ++ i가 스레드로부터 안전합니까? (0) | 2020.09.06 |
비밀 키를 문자열로 또는 그 반대로 변환 (0) | 2020.09.06 |
Java로 자체 반복자를 작성할 수 있습니까? (0) | 2020.09.06 |
개수 및 그룹화 기준에 해당하는 Django (0) | 2020.09.06 |