spano
spano

Reputation: 374

Relative Path Java

I've been having some trouble with an assigment in Java. It's a program that reads level-definitions from txt files. It also reads images. It works so that I have a "resources" folder (inside the program folder) and inside it all the folders/files that I need. Here is an example of a resource folder:

resources

  background_images

    clouds.png

    jungle.jpg

    night.jpg

  block_images

    leopard.jp

    zebra.jpg

  definitions

    level_definitions.txt

Inside the level_definitions.txt, there are all kinds of names of other files to which you should redirect, such as

background_images/night.jpg  or  definitions/moon_block_definitions.txt

This is the program pretty much, and I was able to code it, it works just fine.

At the end of the assignment though, they added this note:

A note on file locations

All the file names specified in the levels and block definition files should be relative to the class path. The reason we want them to be relative to the class path is that later we will be able to read the files from inside a jar, something we can not do with regular File references.

To get an input stream relative to the class path (even if it's inside a jar), use the following:

InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("image.png");
The idea is to keep a folder with files(definitions and images) and then add that folder to the class path when running the JVM:

java -cp bin:resources ... 
If you don't add the resources folder to you class path you wont be able to load them with the command from above.

I really have no idea what they meant by this, and how should I change my code. (my professors are not answering and the assignment is due in just a few days).

Here is how my code reads the files right now:

This is how I read the main file:

java.io.Reader reader = null;
try {
    reader = new InputStreamReader(new FileInputStream("resources/definitions/level_definitions.txt"));
} catch (FileNotFoundException e) {
    e.printStackTrace();
} 
is = new BufferedReader(reader);

This is how I read the other files:

// blocks txt
reader = new InputStreamReader(new FileInputStream("resources/" + stringPath)); 
is = new BufferedReader(reader);

// images
File pathToFile = new File("resources/" + stringPath);
try {
   backgroundImage = ImageIO.read(pathToFile);
} catch (IOException e) {
   e.printStackTrace();
}

Now, I have tried to change into the following:

    java.io.Reader reader = null;
    try {
        reader = new InputStreamReader(ClassLoader.getSystemClassLoader().getResourceAsStream("definitions/level_definitions.txt"););
    } finally {
    } 
    is = new BufferedReader(reader);
    
    
    
    // blocks txt
    reader = new InputStreamReader(ClassLoader.getSystemClassLoader().getResourceAsStream(stringPath);); 
    is = new BufferedReader(reader);
    
    // images
    File pathToFile = new File("resources/" + stringPath);
    try {
       backgroundImage = ImageIO.read(ClassLoader.getSystemClassLoader().getResourceAsStream(stringPath););
    } catch (IOException e) {
       e.printStackTrace();
    }

But of course, it's not working, the program simply doesn't run.

The question is, anyone understands what my professors exactly meant? Any advice on how to change my code accordingly so that it is "relative to classpath"??

Thank you!

Upvotes: 1

Views: 138

Answers (1)

Joop Eggen
Joop Eggen

Reputation: 109547

A resource is not file system File. Resources reside with the .class files possibly inside a .jar.

(Path is a generalisation of both File, resources and even more.)

The resource path "definitions/level_definitions.txt" seems correct. If you build a .jar, you might inspect it with WinZip, 7zip or other tools, as it is just a zip file. There should be a top level directory definitions.

(Probably resources is a root directory for non-java resources.)

The path must be case sensitive and the separator the forward slash (/).

One pretty frequent error on Windows is that the extension is not shown and one gets created files like level_definitions.txt.txt.

The InputStreamReader wraps a binary data InputStream and as Reader returns text. For that one can add the encoding (Charset) of the binary data. You use the default without encoding, so it uses the platform encoding.

If your program runs on another platform it still uses the same resource text file, but might apply a wrong encoding. So better use the encoding of the resource text: for Italy "Windows-2152" or the global "UTF-8". Check it with a good cafè.

Upvotes: 1

Related Questions