views:

77

answers:

3

Lots of confusion in this topic. Several Questions have been asked. Things still seem unclear. ClassLoader, Absolute File Paths etc etc

Suppose I have a project directory structure as,

MyProject--
            --dist        
            --lib
            --src
            --test

I have a resource say "txtfile.txt" in "lib/txt" directory. I want to access it in a system independent way. I need the absolute path of the project. So I can code the path as abspath+"/lib/Dictionary/txtfile.txt"

Suppose I do this

 java.io.File file = new java.io.File("");   //Dummy file
    String  abspath=file.getAbsolutePath();

I get the current working directory which is not necessarily project root.

Suppose I execute the final 'prj.jar' from the 'dist' folder which also contains "lib/txt/txtfile.txt" directory structure and resource,It should work here too. I should absolute path of dist folder.

Hope the problem is clear.

+2  A: 

You should really be using getResource() or getResourceAsStream() using your class loader for this sort of thing. In particular, these methods use your ClassLoader to determine the search context for resources within your project.

Specify something like getClass().getResource("lib/txtfile.txt") in order to pick up the text file.

To clarify: instead of thinking about how to get the path of the resource you ought to be thinking about getting the resource -- in this case a file in a directory somewhere (possibly inside your JAR). It's not necessary to know some absolute path in this case, only some URL to get at the file, and the ClassLoader will return this URL for you. If you want to open a stream to the file you can do this directly without messing around with a URL using getResourceAsStream.

The resources you're trying to access through the ClassLoader need to be on the Class-Path (configured in the Manifest of your JAR file). This is critical! The ClassLoader uses the Class-Path to find the resources, so if you don't provide enough context in the Class-Path it won't be able to find anything. If you add . the ClassLoader should resolve anything inside or outside of the JAR depending on how you refer to the resource, though you can certainly be more specific.

Referring to the resource prefixed with a . will cause the ClassLoader to also look for files outside of the JAR, while not prefixing the resource path with a period will direct the ClassLoader to look only inside the JAR file.

That means if you have some file inside the JAR in a directory lib with name foo.txt and you want to get the resource then you'd run getResource("lib/foo.txt");

If the same resource were outside the JAR you'd run getResource("./lib/foo.txt");

Mark E
Mark as I mentioned,I have already tried doing it will class loaders. Could you please post some snippet as to how to get about with it in my case?
Myth17
@MArk I understood the fact that it has to be dealt by the class loader. but how? java.net.URL url =getClass().getResource("lib/txtfile.txt");returns a null URL for me!
Myth17
@Mark The dist folder had a prj.jar + a "lib/txt/txtfile" resource. ( resource shipped outside jar )I plan to tar the dist folder in the end to distribute it
Myth17
@Myth17, in that case you need to add "." to the class path in the Manifest for the JAR and the call should be `getResource("lib/txt/txtfile")`
Mark E
@MArkI added thisjava.net.URL url=getClass().getClassLoader().getResource("english.txt"); java.net.URL url2 =getClass().getClassLoader().getResource("common-misspells.txt");where lib/Dictionary was in my classpath already.sc.initialize(url.getPath(),url2.getPath());where initialize was a library method I have to use.This works when I compile from netbeans but the jar file in dist folder is still unable to find the dictionary files(although they are present there too).Even The MANIFEST.MF has included :Class-Path: lib/jaspellbin.jar lib/Dictionary
Myth17
@Myth17: if lib/Dictionary is outside the JAR you still need to add `.` to the classpath, I suppose what you really want to add is `./lib/Dictionary`.
Mark E
Thanks @MArk. Problem solved ! :)
Myth17
@Myth17, no problem, I'm going to clean up these comments into the actual answer and delete some of the extra discussion here -- I think it'll make for a more useable answer, suggest you do the same by moving some of the trial/error into your actual question.
Mark E
A: 

@Mark is correct. That is by far the simplest and most robust approach.

However, if you really have to have a File, then your best bet is to try the following:

  • turn the contents of the System property "java.class.path" into a list of pathnames,
  • identify the JAR pathname in the list based on its filename,
  • figure out what "../.." is relative to the JAR pathname to give you the "project" directory, and
  • build your target path relative to the project directory.

Another alternative is to embed the project directory name in a wrapper script and set it as a system property using a -D option. It is also possible to have a wrapper script figure out its own absolute pathname; e.g. using whence.

Stephen C
A: 

First, make sure the lib directory is in your classpath. You can do this by adding the command line parameter in your startup script:

$JAVA_HOME/bin/java -classpath .:lib com.example.MyMainClass

save this as MyProject/start.sh or any os dependent script.

Then you can access the textfile.txt (as rightly mentioned by Mark) as:

// if you want this as a File
URL res = getClass().getClassLoader().getResource("text/textfile.txt");
File f = new File(res.getFile());

// As InputStream
InputStream in = getClass().getClassLoader()
        .getResourceAsStream("text/textfile.txt");
naikus