Java dir/files 列表

Java dir/files list

我试图列出某个目录中的所有目录和文件,但是 "D:\data" 有效,而 "D:\" 无效。 "D"是辅助磁盘。

这是例外情况:

Exception in thread "main" java.lang.NullPointerException
    at java.util.Objects.requireNonNull(Objects.java:203)
    at java.util.Arrays$ArrayList.<init>(Arrays.java:3813)
    at java.util.Arrays.asList(Arrays.java:3800)
    at project.1.scavenger.listf(scavenger.java:19)
    at project.1.scavenger.listf(scavenger.java:30)
    at project.1.scavenger.listf(scavenger.java:30)
    at project.1.main(Project1.java:28)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)

代码:

public static List<File> listf(String directoryName) throws IOException {
    File directory = new File(directoryName);
    List<File> resultList = new ArrayList<File>();

    // get all the files from a directory
    File[] fList = directory.listFiles();
    resultList.addAll(Arrays.asList(fList));
    for (File file : fList) {
        if (file.isFile()) {
            System.out.println(file.getAbsolutePath());
            try {
                System.out.println(scavenger.checkmime(file.getAbsolutePath()));
            } catch (Exception ex) {
            }
        } else if (file.isDirectory()) {
            resultList.addAll(listf(file.getAbsolutePath()));
        }
    }
    // System.out.println(fList);
    return resultList;
}

public static String checkmime(String fl) throws MalformedURLException, IOException {
    File file = new File(fl);
    String mimeType = file.toURL().openConnection().getContentType();
    // System.out.println(mimeType);
    return mimeType;
}

我的代码有什么问题?

已从您的版本中删除错误

在你的递归中,你永远不会要求空值。这样做,它应该 运行 像这样:

  public static List<File> listf(String directoryName) throws IOException {
    File directory = new File(directoryName);

    List<File> resultList = new ArrayList<>();

    // get all the files from a directory
    File[] fList = directory.listFiles();
    // this was missing
    if (fList == null) {
      return null;
    }
    resultList.addAll(Arrays.asList(fList));
    for (File file : fList) {
      if (file.isFile()) {
        System.out.println(file.getAbsolutePath());
        try {
          System.out.println(checkmime(file.getAbsolutePath()));
        } catch (Exception ex) {

        }
      } else if (file.isDirectory()) {
        // ask here if it was null
        List<File> files = listf(file.getAbsolutePath());
        if (files != null) {
          resultList.addAll(files);
        }
      }
    }
    //System.out.println(fList);
    return resultList;
  }

为什么 D:\data 有效而 D:\ 无效

在 Windows 系统的每个驱动器根目录中都有一个名为 $RECYCLE.BIN 的隐藏文件夹结构。在这个文件夹中 windows 为每个用户 (sid) 存储一个自己的文件夹,其中包含已删除的数据(指向它的链接)。但普通用户只能获取第一层,不能获取用户文件夹(名称为sid值)。

(德语 Windows:Papierkorb = 垃圾)

一个可能更好的解决方案:

在树中进行此类搜索的一种可能更好的方法是在目录树上创建迭代器(如复合迭代器)。此解决方案也仅使用 Java NIO 功能,因此平台应该是可变的(尚未测试!),例如。 Linux.

DirectoryTreeIterator.java

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;

public class DirectoryTreeIterator implements Iterator<Path> {

  private final Deque<Iterator<Path>> deque = new ArrayDeque<>();

  public DirectoryTreeIterator(Iterator<Path> it) {
    deque.push(it);
  }

  @Override
  public boolean hasNext() {
    if (deque.isEmpty()) {
      return false;
    } else {
      Iterator<Path> it = deque.peek();
      if (!it.hasNext()) {
        deque.pop();
        return hasNext();
      } else {
        return true;
      }
    }
  }

  @Override
  public Path next() {
    if (hasNext()) {
      Iterator<Path> it = deque.peek();
      Path p = it.next();
      try {
        // here is the magic recursive on only filtered paths
        if (Files.isDirectory(p) && Files.isReadable(p) && !Files.isHidden(p)) {
          deque.push(Files.newDirectoryStream(p).iterator());
        }
      } catch (IOException ex) {
        throw new UncheckedIOException(ex);
      }
      return p;
    } else {
      return null;
    }
  }

}

然后你就可以像魅力一样使用它了:

FileLister.java

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;

public class FileLister {

  public static void main(String[] args) throws IOException {
    Path p = Paths.get("D:\");

    Iterator<Path> it = Files.newDirectoryStream(p).iterator();
    DirectoryTreeIterator dti = new DirectoryTreeIterator(it);
    while (dti.hasNext()) {
      Path path = dti.next();
      if (!Files.isDirectory(path)) {
        String mime = Files.probeContentType(path);
        System.out.println("Mime of File "
                + path.getFileName() + " is: " + mime);
      }
    }
  }
}

如果您将此代码添加到 directory.listFiles() 调用的正下方:

if (fList == null) {
    System.out.println("Couldn't read files in directory: " + directoryName);
    return resultList;
}

然后你会收到这样的消息:

Couldn't read files in directory: G:$RECYCLE.BIN\Windows SID

Windows SIDs 是 security identifier 用于您本地计算机上的用户。 因此,这意味着您当前的用户无权读取 "recycle bin" 目录中的此目录(它属于不同的用户),因此 listFiles() returns null 而不是 String[].

您可以保留支票和我发布的消息,或者您可以采用不同的方式来处理 "unreadable" 目录。

关于 "D:\" 失败而 "D:\data" 失败的原因:

  • "D:\" 包含提到的 "$RECYCLE.BIN" 目录,访问受限
  • "D:\data" 没有不允许当前用户访问的目录 access/read,因此 listFiles() 从未返回 null.