0

I am programming code that searches my computer's storage for a specific file (or multiple of the same name) indicated by a starting path, all of which is user console inputted. My code seems to work fine for some testing but then I when I tried using a more general directory (C:\Users\andy) to search for a file, i get this null pointer exception below.

Exception in thread "main" java.lang.NullPointerException
    at FindFile.search(FindFile.java:44)
    at FindFile.search(FindFile.java:48)
    at FindFile.search(FindFile.java:48)
    at FindFile.search(FindFile.java:48)
    at FindFile.directorySearch(FindFile.java:32)
    at Driver.main(Driver.java:33)

The program runs for a quite a bit of time while it searches through my C drive but then after a few seconds I get thrown the exception above. I am totally lost and any help would be appreciated! (sorry i am new at this)

44: for (File temp : filename.listFiles()

48: search(temp);

32: search(dir);

33: fileSearch.directorySearch(targetFile, pathToSearch);

The class that contains the problematic code:

public class Driver {

    public static void main(String[] args) {

        String targetFile = "";
        String pathToSearch = "";
        int maxNumber = 0;

        Scanner input = new Scanner(System.in);


            System.out.println("max number of files to look for");


                maxNumber = input.nextInt();

                System.out.println("directory to start in");
                pathToSearch = input.next();

                System.out.println("What is the file name");
                targetFile = input.next();

                FindFile fileSearch = new FindFile(maxNumber);


                try {

                    fileSearch.directorySearch(targetFile, pathToSearch);

                } catch (IllegalArgumentException e) {
                    System.out.println("you have reach max number of files found");

                }

                int count = fileSearch.getFileResult().size();
                if (count == 0) {
                    System.out.println("no results of that file was found");
                } else {
                    System.out.println("found " + count + "of file " + targetFile);
                    for (String match : fileSearch.getFileResult()) {
                        System.out.println("location: " + match);
                    }
                }



    }
}


public class FindFile {

    private int maxFiles;
    private List<String> fileResult = new ArrayList<String>();
    private String nameOfFile;
    private int currentNumOfFiles = 0;

    /*
     * accepts the max number of files to find
     */
    public FindFile(int maxNum) {
        maxFiles = maxNum;

    }

    public FindFile() {

    }

    /*
     * @param target file name to look for and directory to start search
     */
    public void directorySearch(String target, String directory) {

        File dir = new File(directory);
        setNameOfFile(target);
        if (dir.isDirectory()) {
            search(dir);
        } else {
            System.out.println("not a directory ");
        }
    }

    public void search(File filename) throws IllegalArgumentException {
        if (filename.isDirectory()) {
            System.out.println("searching directory..." + filename.getAbsoluteFile());
            System.out.println();

            if (filename.canRead()) {
                for (File temp : filename.listFiles()) {
                    if (currentNumOfFiles == maxFiles) {
                        throw new IllegalArgumentException();
                    } else if (temp.isDirectory()) {
                        search(temp);

                    } else {

                        if (getNameOfFile().equals(temp.getName().toLowerCase())) {
                            fileResult.add(temp.getAbsolutePath().toString());
                            currentNumOfFiles = getFileResult().size();
                        }
                    }

                }
            } else {
                System.out.println("cannot read into this directory");
            }
        }

    }

    public int getCount() {
        return currentNumOfFiles;
    }

    public int getMaxFiles() {
        return maxFiles;
    }

    public void setMaxFiles(int maxFiles) {
        this.maxFiles = maxFiles;
    }

    public List<String> getFileResult() {
        return fileResult;
    }

    public String getNameOfFile() {
        return nameOfFile;
    }

    public void setNameOfFile(String nameOfFile) {
        this.nameOfFile = nameOfFile;
    }

    public int getCurrentNumOfFiles() {
        return currentNumOfFiles;
    }

    public void setCurrentNumOfFiles(int currentNumOfFiles) {
        this.currentNumOfFiles = currentNumOfFiles;
    }

}
BDL
  • 21,052
  • 22
  • 49
  • 55
bpham93
  • 1
  • 3

2 Answers2

1

In the line

for (File temp : filename.listFiles()) {

the method filename.listFiles() can sometimes return null, which leads to a NullPointerException in the for Loop.

This can e.g. arise, if that directory existed shortly before, but was removed inbetween. If you scan your C: drive this can occur, since typically some programs run in the Background, which can do this.

Thomas Philipp
  • 261
  • 1
  • 5
  • ohhh okok that makes sense now. so i just need to check to see if that method is null before i can move on then right? – bpham93 Nov 11 '16 at 13:52
  • Yes. Assign filename.listFiles() in a temporary variable, check for null, and do the for Loop only if not null. – Thomas Philipp Nov 11 '16 at 13:57
  • hm okay i tried that. i added "if(filename.list().length > 0)" after checking if file is a directory (first line of the search method) but i still get an error...Am i not checking it in the correct location? – bpham93 Nov 11 '16 at 14:44
  • Still you are calling the method ".length()" on null, which provokes a NullPointerException. Assign filename.list() to a temporary variable and check for null before doing a for Loop on this. – Thomas Philipp Nov 17 '16 at 13:36
0

As @Thomas notes, the listFiles() can return null. According to the javadocs this can occur:

... if [the File] does not denote a directory, or if an I/O error occurs.

Here are some possibilities:

  1. There is a race condition whereby the directory is deleted, replaced with a file or made read-only while the parent directory is being iterated.

  2. The directory cannot be listed despite canRead() returning true. There are scenarios1 where this call may return true but the file or directory cannot be read anyway.

  3. There is some other other cause for the IOException; e.g. a network error or hard disk IO error.

You should not assume that (canRead() && isDirectory()) == true means that you won't get a null. Test for the null.


1 - For example: http://bugs.java.com/view_bug.do?bug_id=6203387. I also recall seeing some rather strange behavior happen when a syscall is blocked by SELinux in "enforcing" mode. That could have a bearing here.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • thanks for that! i having trouble figuring out how to check for null since its a file object... – bpham93 Nov 11 '16 at 15:04
  • Assign it to a temporary variable and then use `tempVar == null`. There is nothing special about either File objects or the result of `listFiles()`. – Stephen C Nov 11 '16 at 21:47