Search code examples
javafiledir

Java dir/files list


I am trying to list all directories and files within a certain directory, but while "D:\data" works, "D:\" doesn't. "D" is a secondary disk.

This is the exception:

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)

Code:

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;
}

What's wrong with my code?


Solution

  • Removed error from your version

    In your recursion you never ask for null values. Do it and it should run like this:

      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;
      }
    

    Why D:\data works and D:\ not

    In every root of a drive in a Windows System is a hidden folder structure called $RECYCLE.BIN. In this folder windows stores for each user (sid) an own folder with deleted data (links to it). But a normal user is only allowed to get the first level and not the user folder (with sid value as name).

    (German Windows: Papierkorb = Trash)

    enter image description here

    A maybe much better solution:

    A maybe better way of doing such searchings in tree's is to create an Iterator over the directory tree (like a composite iterator). This solution also uses only Java NIO features, so the platform should be changeable (haven't tested!) to for ex. 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;
        }
      }
    
    }
    

    Then you are able to use it like a charm:

    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);
          }
        }
      }
    }