Java 在Scala中递归删除目录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25999255/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 01:40:06  来源:igfitidea点击:

Delete directory recursively in Scala

javascalafile

提问by Michael

I am writing the following (with Scala 2.10 and Java 6):

我正在编写以下内容(使用 Scala 2.10 和 Java 6):

import java.io._

def delete(file: File) {
  if (file.isDirectory) 
    Option(file.listFiles).map(_.toList).getOrElse(Nil).foreach(delete(_))
  file.delete
}

How would you improve it ? The code seems working but it ignores the return value of java.io.File.delete. Can it be done easier with scala.ioinstead of java.io?

你会如何改进它?该代码似乎有效,但它忽略了java.io.File.delete. 可以用scala.io而不是更容易java.io吗?

回答by Gabriele Petronella

Using scala IO

使用Scala IO

import scalax.file.Path

val path = Path.fromString("/tmp/testfile")    
try {
  path.deleteRecursively(continueOnFailure = false) 
} catch {
  case e: IOException => // some file could not be deleted
}

or better, you could use a Try

或者更好,你可以使用 Try

val path: Path = Path ("/tmp/file")
Try(path.deleteRecursively(continueOnFailure = false))

which will either result in a Success[Int]containing the number of files deleted, or a Failure[IOException].

这将导致Success[Int]包含已删除文件数的 a 或Failure[IOException].

回答by roterl

Using java 6 without using dependencies this is pretty much the only way to do so.
The problem with your function is that it return Unit (which I btw would explicit note it using def delete(file: File): Unit = {

在不使用依赖项的情况下使用 java 6 这几乎是唯一的方法。
您的函数的问题在于它返回 Unit (顺便说一句,我会使用def delete(file: File): Unit = {

I took your code and modify it to return map from file name to the deleting status.

我接受了您的代码并对其进行了修改,以将映射从文件名返回到删除状态。

def delete(file: File): Array[(String, Boolean)] = {
  Option(file.listFiles).map(_.flatMap(f => delete(f))).getOrElse(Array()) :+ (file.getPath -> file.delete)
}

回答by Garrett Hall

Try this code that throws an exception if it fails:

试试这个如果失败就会抛出异常的代码:

def deleteRecursively(file: File): Unit = {
  if (file.isDirectory) {
    file.listFiles.foreach(deleteRecursively)
  }
  if (file.exists && !file.delete) {
    throw new Exception(s"Unable to delete ${file.getAbsolutePath}")
  }
}

You could also fold or map over the delete if you want to return a value for all the deletes.

如果您想为所有删除返回一个值,您还可以折叠或映射删除。

回答by Dan Ciborowski - MSFT

From http://alvinalexander.com/blog/post/java/java-io-faq-how-delete-directory-tree

来自 http://alvinalexander.com/blog/post/java/java-io-faq-how-delete-directory-tree

Using Apache Common IO

使用 Apache 通用 IO

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
public void deleteDirectory(String directoryName)
throws IOException
{
  try
  {
    FileUtils.deleteDirectory(new File(directoryName));
  }
  catch (IOException ioe)
  {
    // log the exception here
    ioe.printStackTrace();
    throw ioe;
  }
}

The Scala one can just do this...

Scala 可以做到这一点......

import org.apache.commons.io.FileUtils
import org.apache.commons.io.filefilter.WildcardFileFilter
FileUtils.deleteDirectory(new File(outputFile))

Maven Repo Imports

Maven 回购进口

回答by Pramit

This one uses java.io but one can delete directories matching it with wildcard string which may or may not contain any content within it.

这个使用 java.io 但可以删除与通配符字符串匹配的目录,其中可能包含也可能不包含任何内容。

 for (file <- new File("<path as String>").listFiles;
        if( file.getName() matches("[1-9]*"))) FileUtils.deleteDirectory(file)

Directory structure e.g. * A/1/, A/2/, A/300/ ... thats why the regex String: [1-9]*, couldn't find a File API in scala which supports regex(may be i missed something).

目录结构,例如 * A/1/, A/2/, A/300/ ... 这就是为什么 regex String: [1-9]*, 在 Scala 中找不到支持正则表达式的文件 API(可能是我错过了一些东西)。

回答by Julian Peeters

Getting little lengthy, but here's one that combines the recursivity of Garrette's solution with the npe-safety of the original question.

有点冗长,但这里有一个将 Garrette 解决方案的递归性与原始问题的 npe 安全性相结合的方法。

def deleteFile(path: String) = {
  val penultimateFile = new File(path.split('/').take(2).mkString("/"))
  def getFiles(f: File): Set[File] = {
    Option(f.listFiles)
      .map(a => a.toSet)
      .getOrElse(Set.empty)
  }
  def getRecursively(f: File): Set[File] = {
    val files = getFiles(f)
    val subDirectories = files.filter(path => path.isDirectory)
    subDirectories.flatMap(getRecursively) ++ files + penultimateFile
  }
  getRecursively(penultimateFile).foreach(file => {
    if (getFiles(file).isEmpty && file.getAbsoluteFile().exists) file.delete
  })
}

回答by Slavik Muz

This is recursive method that clean all in directory, and return count of deleted files

这是清除目录中所有内容的递归方法,并返回已删除文件的计数

def cleanDir(dir: File): Int = {

      @tailrec
      def loop(list: Array[File], deletedFiles: Int): Int = {
        if (list.isEmpty) deletedFiles
        else {
          if (list.head.isDirectory && !list.head.listFiles().isEmpty) {
            loop(list.head.listFiles() ++ list.tail ++ Array(list.head), deletedFiles)
          } else {
            val isDeleted = list.head.delete()
            if (isDeleted) loop(list.tail, deletedFiles + 1)
            else loop(list.tail, deletedFiles)
          }
        }
      }

      loop(dir.listFiles(), 0)
    }

回答by Chris Martin

To add to Slavik Muz's answer:

添加到 Slavik Muz 的答案:

def deleteFile(file: File): Boolean = {

  def childrenOf(file: File): List[File] = Option(file.listFiles()).getOrElse(Array.empty).toList

  @annotation.tailrec
  def loop(files: List[File]): Boolean = files match {

    case Nil ? true

    case child :: parents if child.isDirectory && child.listFiles().nonEmpty ?
      loop((childrenOf(child) :+ child) ++ parents)

    case fileOrEmptyDir :: rest ?
      println(s"deleting $fileOrEmptyDir")
      fileOrEmptyDir.delete()
      loop(rest)

  }

  if (!file.exists()) false
  else loop(childrenOf(file) :+ file)
}

回答by Vladimir Matveev

Using the Java NIO.2 API:

使用 Java NIO.2 API:

import java.nio.file.{Files, Paths, Path, SimpleFileVisitor, FileVisitResult}
import java.nio.file.attribute.BasicFileAttributes

def remove(root: Path): Unit = {
  Files.walkFileTree(root, new SimpleFileVisitor[Path] {
    override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = {
      Files.delete(file)
      FileVisitResult.CONTINUE
    }
    override def postVisitDirectory(dir: Path, exc: IOException): FileVisitResult = {
      Files.delete(dir)
      FileVisitResult.CONTINUE
    }
  })
}

remove(Paths.get("/tmp/testdir"))

Really, it's a pity that the NIO.2 API is with us for so many years and yet few people are using it, even though it is really superior to the old FileAPI.

真的很遗憾,NIO.2 API 已经存在了这么多年,却很少有人使用它,尽管它确实优于旧的FileAPI。

回答by Mike Slinn

Expanding on Vladimir Matveev's NIO2 solution:

扩展 Vladimir Matveev 的 NIO2 解决方案:

object Util {
  import java.io.IOException
  import java.nio.file.{Files, Paths, Path, SimpleFileVisitor, FileVisitResult}
  import java.nio.file.attribute.BasicFileAttributes

  def remove(root: Path, deleteRoot: Boolean = true): Unit =
    Files.walkFileTree(root, new SimpleFileVisitor[Path] {
      override def visitFile(file: Path, attributes: BasicFileAttributes): FileVisitResult = {
        Files.delete(file)
        FileVisitResult.CONTINUE
      }

      override def postVisitDirectory(dir: Path, exception: IOException): FileVisitResult = {
        if (deleteRoot) Files.delete(dir)
        FileVisitResult.CONTINUE
      }
    })

  def removeUnder(string: String): Unit = remove(Paths.get(string), deleteRoot=false)

  def removeAll(string: String): Unit = remove(Paths.get(string))

  def removeUnder(file: java.io.File): Unit = remove(file.toPath, deleteRoot=false)

  def removeAll(file: java.io.File): Unit = remove(file.toPath)
}