1

该程序删除给定节点下的所有文件和文件夹。

*编辑*

我在驱动器 K 上有以下“测试”目录结构:

Folder K:\garbage\
f_00000b (file)
f_00000f ( " )
f_0000b3 ( " )
dir1    [FOLDER]

Folder K:\garbage\dir1\
abc.pdf (file)
b12.pdf (file)
b36.pdf (file)
dir2   [FOLDER]

Folder K:\garbage\dir1\dir2\
A.pdf   (file)
a1.pdf  (file)
A2.pdf  (file)

*结束编辑*

程序有效,因为我偶然发现了“try-with-resources”,这条线被所有 /////////////////////////////////////////////////////////////////////// .

import java.io.IOError;
import java.io.IOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import javax.swing.JOptionPane;

public class CreatingDirectories {

    public static void main(String[] args) {

      deleteEverythingBelowThisNode(Paths.get("K:/garbage/dir1/dir2"));
    }

    static void deleteAllFilesIn(String ps){

      Path p = Paths.get(ps);

      try ////////////////////////////////////////////////////////////////
         (DirectoryStream<Path> paths = Files.newDirectoryStream(p)) /////
      { //////////////////////////////////////////////////////////////////

        for(Path q: paths)
          Files.delete(q);

      }catch(NotDirectoryException e){
        System.out.println("Not directory: " + p.toString() + "--" + e);
      }catch(DirectoryNotEmptyException e){
        System.out.println("Not empty: " + p.toString() + "--" + e);
      }
      catch(IOException e){
        System.out.println("IO: " + p.toString() + "--" + e);
      }
      catch(IOError e){
        System.out.println("IO ERROR: " + e);
      }
    }

    static void deleteEverythingBelowThisNode(Path p){

      String            sep        = p.getFileSystem().getSeparator();
      ArrayList<String> pathPieces = new ArrayList<>() ;
      String []         paths      = new String[p.getNameCount()];

      for(int i = 0 ; i < p.getNameCount() ; i++){
        pathPieces.add(p.getName(i).toString());
        paths[i] = p.getRoot().toString();
      }

      for(int i = 0; i < p.getNameCount() ; i++)
        for(int k = 0; k <= i; k++)
          paths[i] += pathPieces.get(k) + sep;

      for(int k = p.getNameCount() - 1; k >= 0; k--)
        deleteAllFilesIn(paths[k]);
    }
}

我知道“尝试资源”是必要的:程序可以使用它,而不是没有它。

但我不明白为什么,也不知道它是如何解决我现在描述的原始问题的。

我最初将“资源”放在 try-block 上方,就像这样,这看起来很自然:

      DirectoryStream<Path> paths = Files.newDirectoryStream(p);
      try {
           for...

除了如上所示移动那一行之外,程序结构其他方面相同,所有文件和子文件夹已成功从文件夹中删除,但DirectoryNotEmptyException被抛出。Windows Explorer 确认程序因异常终止后目录为空。

为什么在空目录上抛出异常?

马的口中,“try-with-resources 语句......声明......一个对象......在语句末尾关闭。”

关闭发生在语句的末尾,所以在循环的末尾。即使使用 try-with-resources 怎么没有发生异常?

就像现在一样,在遍历整个节点之后,它下面的所有内容都被删除了。

那么 try-with-resources 实际上做了什么来启用删除一个没有 try-with-resources 就无法删除的空文件夹?

这些似乎不是愚蠢的问题或微不足道的情况。

DirectoryNotEmptyException无论如何都确实发生了,但是 try-with-resources 以某种方式处理了它?我不敢相信我在问这个问题,因为这看起来确实是一个愚蠢的问题,但究竟发生了什么让程序按预期运行呢?

4

3 回答 3

2

在 Windows 上,您无法删除仍处于打开状态的文件或目录。(另一方面,在 Unix 上,这不是问题 - 当您删除文件时,文件将从目录结构中删除,当您关闭文件时,文件将从磁盘中删除。但这是在 Unix 上。)

因此,如果您不使用 try-with-resources 语句来关闭目录流,那么在您尝试删除父目录中的文件的那一刻,您仍然会打开子目录,并且尝试到仍然存在的子目录打开会失败。由于您忽略异常(您只是打印它们),因此随后删除父目录的尝试也将失败,DirectoryNotEmptyException因为您没有删除所有子目录。

您可以验证是否确实如此。当您使用 try-with-resources 时,请确保在删除目录中的所有文件后显式关闭目录流(使用paths.close();

这应该与 try-with-resources 块具有相同的效果(除非发生异常 - 为了保证与 try-with-resources 完全相同的行为,您需要放入paths.close();一个finally块)。

于 2014-03-01T03:01:15.223 回答
1

Erwin 解释了您的问题,但您在列表末尾也有一个相当严重的问题,位于:

   for(int k = p.getNameCount() - 1; k >= 0; k--)
        deleteAllFilesIn(paths[k]);

您创建一个路径部分列表,例如,其中的部分将是:

  • k:/垃圾/dir1/dir2
  • k:/垃圾/dir1
  • k:/垃圾
  • 克:/

这意味着您最终会尝试删除 k: 中的所有内容。它将尝试删除 k:\ 中的所有内容(所有文件;如果有任何非空子目录,它将整体失败)。

假设您只想删除最低级别的文件,您可能想要更改deleteEverythingBelowThisNode()功能。

于 2014-03-01T03:07:22.997 回答
0

(我希望可以“回答我自己的问题”以使线程的“底线”显示最终的工作原理。这样,任何查看线程的人都不必努力寻找解决方案。)

无论如何,这是deleteAllFilesBelowThisNode@Erwin 的建议。

static void deleteAllFilesBelowThisNode(String ps) throws IOException{

  Path p = Paths.get(ps);

  try (DirectoryStream<Path> paths = Files.newDirectoryStream(p))
  {
    for(Path q: paths){
    
      if(JOptionPane.showConfirmDialog(null,"Deleting " + q.toString(),"",
           JOptionPane.OK_CANCEL_OPTION) 
        != JOptionPane.OK_OPTION)
                                  System.exit(9);
      
      Files.delete(q);
      System.out.println(q.toString() + " deleted");
    }
  }
  finally{
    JOptionPane.showMessageDialog(null,"AHA!");
  }
}

我添加了“啊哈!” 因为我终于意识到发生了什么。

编辑

我把昨天骄傲地添加的所有东西都拿出来了,因为我再次发现自己像水银一样稠密。星球、金属、汽车……什么evvvvvvvvvvs。

我忘记了对 的三个单独的调用DeleteAllFilesBelowThisNode,这真的让我很困惑。哎呀,这是我该死的程序,但是……以林还林,等等。通过不包括整个程序,我愚弄了我。骗了我好。很好。

我真的不是个白痴。

*结束编辑

但我留下了这个:

谢谢你,欧文!

另一个编辑

这是输出,以供理解:

Delete all entries beneath K:\garbage\dir1\dir2\
  deleting K:\garbage\dir1\dir2\A.pdf ... deleted
  deleting K:\garbage\dir1\dir2\a1 and 2 ver 2.pdf ... deleted
  deleting K:\garbage\dir1\dir2\A1 and 2.pdf ... deleted
K:\garbage\dir1\dir2\ closed by finally. ----- THUS DELETEABLE

Delete all entries beneath K:\garbage\dir1\
  deleting K:\garbage\dir1\abc.pdf ... deleted
  deleting K:\garbage\dir1\b12.pdf ... deleted
  deleting K:\garbage\dir1\b36.pdf ... deleted
  deleting K:\garbage\dir1\dir2 ... ***DELETED***
K:\garbage\dir1\ closed by finally. ----- THUS DELETEABLE


Delete all entries beneath K:\garbage\
  deleting K:\garbage\dir1 ... ***DELETED***
  deleting K:\garbage\f_00000b ... deleted
  deleting K:\garbage\f_00000f ... deleted
  deleting K:\garbage\f_0000b3 ... deleted
K:\garbage\ closed by finally.

这是整个程序:

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import javax.swing.JOptionPane;

public class CreatingDirectories {

  static void deleteAllFilesBelowThisNode(String ps) throws IOException{

    try (DirectoryStream<Path> paths = Files.newDirectoryStream(Paths.get(ps)))
    {
      for(Path q: paths){
                         System.out.print("deleting " + q.toString() + " ... ");
        if(JOptionPane.showConfirmDialog(null,"Deleting " + q.toString(),"",
             JOptionPane.OK_CANCEL_OPTION) 
          != JOptionPane.OK_OPTION)
                                                               System.exit(9);
        Files.delete(q);
                                                  System.out.println("deleted");
      }
    }
    finally{         
      System.out.println("\n" + ps + " closed by finally.\n");
    }
  }
    
  static void iterativelyDeleteFoldersFromHereUpToRoot(Path p) throws IOException{

    String            sep        = p.getFileSystem().getSeparator();
    ArrayList<String> pathPieces = new ArrayList<>() ;
    String []         paths      = new String[p.getNameCount()];

    for(int i = 0 ; i < p.getNameCount() ; i++){

      pathPieces.add(p.getName(i).toString());

      paths[i] = p.getRoot().toString();
    }

    for(int i = 0; i < p.getNameCount() ; i++)
      for(int k = 0; k <= i; k++)
                                  paths[i] += pathPieces.get(k) + sep;

    for(int k = p.getNameCount() - 1; k >= 0; k--){

      System.out.println("\nDelete all entries beneath " + paths[k].toString());
    
      deleteAllFilesBelowThisNode(paths[k]);
    }
  }
    
  public static void main(String[] args) throws IOException {

    iterativelyDeleteFoldersFromHereUpToRoot(Paths.get("K:/garbage/dir1/dir2"));
  }
}
于 2014-03-02T23:20:53.533 回答