Search code examples
javajarfilewriterbufferedwriter

Write to file outside .jar


My project structure:

project
     out
        file.txt
        myjar.jar
                 Main.class

My code snippet (that doesn't find the file.txt):

BufferedWriter output = new BufferedWriter(new FileWriter("file.txt", true));

output.append(player.toString());
output.close();

How do I make it find file.txt and append text to file.txt ?


Solution

  • There is an idea of the current working directory associated with every process on a computer. When a process starts, it usually has a current working directory. This applies to the JVM process (the process that starts when you run the command java on your computer) as well.

    The relative paths that you specify in various IO class methods are with respect to this current working directory. Here's what the Javadoc of java.io.File says:

    By default the classes in the java.io package always resolve relative pathnames against the current user directory. This directory is named by the system property user.dir, and is typically the directory in which the Java virtual machine was invoked.

    So, what is important is to use the correct working directory when you invoke java. Relative paths (like your file.txt) are those that do not begin with a leading '/' or a drive letter.

    Here is an example:

    Foo.java

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class Foo {
        public static void main(String[] args) throws IOException {
            try (BufferedReader reader = new BufferedReader(new FileReader("Foo.java"))) {
                System.out.println(reader.readLine());
            } 
        }
    }
    

    This class, when run, will try to find Foo.java itself and output its first line, which is: import java.io.BufferedReader;.

    1. Compile this to Foo.class.
    2. Say, folder where Foo.class is stored on your (Linux) computer is /tmp.
    3. You are now on a terminal in /tmp => java Foo.This should print the first line as expected.
    4. cd $HOME.
    5. java -cp /tmp Foo (this is because your class is still in /tmp)

    This fails with:

    Exception in thread "main" java.io.FileNotFoundException: Foo.java (No such file or directory) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.(FileInputStream.java:138) at java.io.FileInputStream.(FileInputStream.java:93) at java.io.FileReader.(FileReader.java:58) at Foo.main(Foo.java:10)

    This is because it tries to find Foo.java in current working directory, which is $HOME and Foo.java itself is in some other folder (/tmp). What is true of BufferedReader is also true of BufferedWriter in your case.

    So, you should run this program from a folder where file.txt resides:

    1. cd project/out
    2. java -cp myjar.jar Main

    A better idea is to always know the location of the file you want to write to. That way, your program may get tied to a particular path on a particular type of computer, but at least you can run it from anywhere on that computer without problems.