Search code examples
javafile-exists

Why does file.exists() always return true if I don't throw FileNotFoundExcetion in the first place


public class Main {

final private static int MAX_RECORD_NUMBER = 20;
final private static int RECORD_LENGTH = 71;

public static void main(String[] args) throws IOException, FileNotFoundException{
    Scanner input = new Scanner(System.in);
    System.out.println("Please input the file location and name.");
    String filepath = input.next();
    File file = new File(filepath); 

    boolean isExisted = file.exists(); // Problem exists here if I delete FileNotFoundException

    RandomAccessFile store = new RandomAccessFile(file, "rw");

    if (!isExisted) {
        String dummy = "Empty record                                                           ";
        for (int i = 0; i < MAX_RECORD_NUMBER; i++) {
            store.writeUTF(dummy);
        }
    }

I am stuck at a minor glitch here. The file.exists() methods will always return true (even the file was really not there) if I didn't throw FileNotFoundException. In this case, if I don't throw FileNotFoundException at the head of the main method, it's unable to writeUTF to that file. This must be a dumb question but I just want to know what's the mechanism behind this. API doesn't help me neither. I really appreciate anyone that could explain to me.

Edit: Sorry, I was unclear before. What I really wanted to ask is why .exists() method always returns true instead of false or other unexpected errors?


Solution

  • You need to realise where this exception is thrown. And the place is this line:

    RandomAccessFile store = new RandomAccessFile(file, "rw");
    

    Take a look at the API of FileNotFoundException and you will know it's thrown just as expected, in the RandomAccessFile constructor.

    Test your logic without the RandomAccessFile, with the following code:

    import java.io.*;
    import java.util.Scanner;
    
    public class Main {
    
        public static void main(String[] args){
            Scanner input = new Scanner(System.in);
            System.out.println("Please input the file location and name.");
            String filepath = input.next();
            File file = new File(filepath); 
            if (file.exists()) System.out.println("EXISTS!"); else System.out.println("DOESN'T EXIST!");
        }
    
    }
    

    Now the first part of the problem should be clear. The function file.exists() works correctly. The flaw in logic comes from the fact, that the RandomAccessFile constructor is able to create the file, but not always. And that's why you need to service the exception. The following is an excerpt from Java 8 API of the constructor:

    FileNotFoundException - if the mode is "r" but the given file object does not denote an existing regular file, or if the mode begins with "rw" but the given file object does not denote an existing, writable regular file and a new regular file of that name cannot be created, or if some other error occurs while opening or creating the file

    So the other part of your code might look like this:

    try {
        RandomAccessFile store = new RandomAccessFile(file, "rw");
        String dummy = "Empty record                                                           ";
        for (int i = 0; i < MAX_RECORD_NUMBER; i++) {
           store.writeUTF(dummy);
        }
    } catch (FileNotFoundException e){
        System.err.println("File cannot be created!");
    }
    

    But this wouldn't be enough, regarding the exception servicing, because you use here the writeUTF(dummy) function. And this function throws:

    IOException - if an I/O error occurs. (As the API of RandomAccessFile says.)

    Thus, you need to service the IOException. For example appending one more catch clause to the existing one, this one:

    catch (IOException e){
        System.err.println("Couldn't write to file!");
    } 
    

    Or you might skip the FileNotFoundException, as it is a subclass of IOException and have just one catch clause with IOException. But, as you can see, here it's quite obvious they stand for two different causes.

    And so eventually your class looks like this:

    import java.io.*;
    import java.util.Scanner;
    
    public class Main {
    
    final private static int MAX_RECORD_NUMBER = 20;
    final private static int RECORD_LENGTH = 71;
    
        public static void main(String[] args){
            Scanner input = new Scanner(System.in);
            System.out.println("Please input the file location and name.");
            String filepath = input.next();
            File file = new File(filepath); 
            //if (file.exists()) System.out.println("EXISTS!"); else System.out.println("DOESN'T EXIST!");
    
            try {
                RandomAccessFile store = new RandomAccessFile(file, "rw");
                String dummy = "Empty record                                                           ";
                for (int i = 0; i < MAX_RECORD_NUMBER; i++) {
                   store.writeUTF(dummy);
                }
            } catch (FileNotFoundException e){
                System.err.println("File cannot be created!");
            } catch (IOException e){
                System.err.println("Couldn't write to file!");
            }
        }
    }
    

    Some parts were not needed. Analyse my solution and it should clarify your mistake. Or ask me for more. This answer is a bit lengthy anyhow.

    One last note. People in other threads got confused with similar things. You can see links to them on the right. To cut a long story short, use the full path for the file. And for more details, check the links.