Uncompiled jar works but compiled doesn't work - java

So in Eclipse this code works:
String file_path = "accounts.accs";
File file = new File("src/puffinlump/folder_lock/"+file_path);
But when I compile it into a JAR I get this error:
Error reading file: java.io.FileNotFoundException: lock\src\puffinlump\folder_lock\accounts.accs (The system cannot find the path specified)
Why is it not working and how can I fix it?

As Obicere said, the working directory is the project directory. You try to access something in the src folder, which probably doesn't exist wherever you exported your JAR. You should create a folder named folder_lock in your project directory with accounts.accs in it, then get your file with:
File file = new File("folder_lock" + File.separator + "accounts.accs");
If you need it in your JAR (which it's being exported to, given that it's in the src folder) then retrieve an InputStream from it like this:
InputStream stream = getClass().getClassLoader().getResourceAsStream("puffinlump/folder_lock/accounts.accs");
If your method is static, use
InputStream stream = MyClass.class.getClassLoader().getResourceAsStream("puffinlump/folder_lock/accounts.accs");
instead, substituting your class name over MyClass.
If you need an URL, you can retrieve one with getResource instead of getResourceAsStream.
Note that your code must be compiled to run - Eclipse compiles it by default every time you save.

Related

getClassLoader().getResource("Configuration.xml").getPath() does not work inside a jar

I've created a maven based java project which has resources directory (src/java/resources) and in it some xml files and maven copies them into target/classes/resources (target/classes is my classpath).
To know the content of an xml file, I use:
new FileInputStream(Main.class.getClassLoader().getResource("Configuration.xml").getPath());
Main.class.getClassLoader().getResource("Configuration.xml").getPath() gives me the full path of the xml: "c:\project...\Configuration.xml".
This works well on intellij.
but when I compile and package the project into a jar file I get:
Exception in thread "main" java.io.FileNotFoundException:
file:\C:\project\target\project-12.50.14-SNAPSHOT-jar-with-dependencies
.jar!\Configuration.xml
(The filename, directory name, or volume label syntax is incorrect)
That because the path: \C:\project\target\project-12.50.14-SNAPSHOT-jar-with-dependencies
.jar!\Configuration.xml cannot be a parameter into FileInputStream().
I cannot replace the getResource() to getResourceAsStream().
I need a way to adjust my jar and resources to work like it work on intellij.
I also change the xml resources files content during run-time so that is another problem with keeping them inside a jar.
Can anyone offer me a solution in which I don't have to change me code, and instead change my resources directory structure, or change the classpath, or something else that will keep my code working?
Thanks.
Update: Changed to use File, not Path.
That is because getResource returns a URL, and not all urls are files on disk, i.e. can be converted to a Path. As javadoc says "Returns [...] an empty string if [path part] does not exist".
If it absolutely must be a File or FileInputStream, because some other code you cannot change requires it, then copy the content to a temporary file:
File file = File.createTempFile("Configuration", ".xml");
try {
try {InputStream in = Main.class.getClassLoader().getResourceAsStream("Configuration.xml")) {
Files.copy(in, file.toPath()); // requires Java 7
}
// use file here, or:
try {FileInputStream in = new FileInputStream(file)) {
// use file stream here
}
} finally {
file.delete();
}
The above code could be optimized to not copy if resource is a file, but since that's only for development mode, and production mode is always a Jar and will always need the copy, using copy in development mode helps test the code.

Eclipse unable to locate file-- FileNotFoundException on File object usage

When I attempt to access a File object in Java using Eclipse, the system sends a FileNotFoundException whenever the file is accessed. I have created the file manually and placed it within Eclipse's file browser. The file does have content, so the problem isn't that it's empty. I am initializing the File with
File file = new File(this.getClass().getResource("save.txt").toString());
and accessing it with
PrintWriter p = new PrintWriter(file);
which sends the error. The stacktrace flows back through nothing except a path of initializations that create this class. The exception is
java.io.FileNotFoundException: file:\C:\Users\Nathaniel\Downloads\ERPGE-Global%20Equestria%20Workspace\Swarm\bin\main\save.txt (The filename, directory name, or volume label syntax is incorrect)
What could be causing this error, and how can it be fixed?
You need to make sure that the resource is included in the project's build path.
You can do this in one of two ways:
Put it in a folder (e.g. "res") then add that folder to the build path. That way, all the files in the folder will be added to the build path.
Put it inside (one of) your source folders. Be aware that if you put it inside a package folder, you'll need to include the relative path to that folder (see below).
Personally I prefer option #1.
Edit: You might also find it useful to have sub-directories of the res folder. If you have a file such as res/images/button.png and you've added the res folder to the build path, you need to access the file with the string "images/button.png".
Edit 2: Fixed some misleading info.
The file needs to be placed in the parent project folder itself and not the source folder. If a file is created without a specified file path, this is where it would be stored.
Provide the actual path to the file and get the file Object. Then you can use it.
File file = new File("C:\Users\Nathaniel\Downloads\save.txt");
PrintWriter p = new PrintWriter(file);
EDIT:
Externalising the File Name:
Create a properties file filedetails.properties in the external folder/package.
fileName=C:\Users\Nathaniel\Downloads\save.txt
Accessing the resource bundle.
ResourceBundle b=ResourceBundle.getBundle("external.filedetails") ;
String fileName=b.getString("fileName");
File file=new File(fileName);

Where does Java put resource files when I JAR my program?

Been looking for this for the past 2 hours and can't find anything (I've found solutions to the same problem but with images, not text files).
Pretty much, I made a program that reads a text file. The file is a list of names and IDs. Using Eclipse, I put the file in my src folder and in the program put the path file to it. Like this:
in = new BufferedReader(new FileReader(curDir+"\\bin\\items.txt"));
Where curDir is the user's current directory (found with System.getProperty("user.dir")).
Now, problem is, the program runs fine when I run it from Eclipse, but when I try to make it a runnable JAR and then run it, the program runs, but the info from the text file does not load. It look like Eclipse is not putting the text file with the JAR.
EDIT: Solved-ish the problem? So the JAR file needs to the in a folder with all the original files? I am so confused, what is a JAR file then?
A more robust way to get a file whether you are running from Eclipse or a JAR is to do
MyClass.getResource("items.txt")
where MyClass is a class in the same package (folder) as the resource you need.
If Eclipse is not putting the file in your JAR you can go to
Run -> Run Configurations -> -> Classpath tab -> Advanced -> Add Folders
Then add the folder containing your file to the classpath. Alternatively, export the Ant script and create a custom build script.
To the point, the FileReader can only read disk file system resources. But a JAR contains classpath resources only. You need to read it as a classpath resource. You need the ClassLoader for this.
Assuming that Foo is your class in the JAR which needs to read the resource and items.txt is put in the classpath root of the JAR, then you should read it as follows (note: leading slash needed!):
InputStream input = Foo.class.getResourceAsStream("/items.txt");
reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
// ...
Or if you want to be independent from the class or runtime context, then use the context class loader which operates relative to the classpath root (note: no leading slash needed!):
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("items.txt");
reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
// ...
(UTF-8 is of course the charset the file is encoded with, else you may see Mojibake)
Get the location of your jar file
Firstly create a folder(say myfolder) and put your files inside it
Consider the following function
public String path(String filename)
{
URL url1 = getClass().getResource("");
String ur=url1.toString();
ur=ur.substring(9);
String truepath[]=ur.split("myjar.jar!");
truepath[0]=truepath[0]+"myfolder/";
truepath[0]=truepath[0].replaceAll("%20"," ");
return truepath[0]+filename;
}//This method will work on Windows and Linux as well.
//You can alternatively use the following line to get the path of your jar file
//classname.class.getProtectionDomain().getCodeSource().getLocation().getPath();
Suppose your jar file is in D:\Test\dist
Then path() will return /D:/Test/dist/myfolder/filename
Now you can place 'myfolder' inside the folder where your jar file is residing
OR
If you want to access some read-only file inside your jar you should copy it to one
of your packages and can access it as
yourClassname.getResource("/packagename/filename.txt");

How to specify relative file path in Java file so that it can still work after the file is put in jar file?

Suppose I have a Java class that needs to access a file with absolute path
/home/gem/projects/bar/resources/test.csv:
package com.example
class Foo {
String filePath = ????? // path to test.csv
String lines = FileInputStream(new File(filePath).readAllLines();
}
Where the path to Foo.java is /home/gem/projects/bar/src/com/example.
Of course I cannot specify absolute path to the resource file. This is because jar file will be distributed as library for any clients to use in their own environments.
Assume the resource file like test.csv is always in the same path relative to project root. When a jar is created containing Foo.class, this jar also contains test.csv in the same relative path ( relative to project root).
What is the way to specify relative path that would work no matter where the project bar is moved to? Also how can I create a jar file (which can be in any location) so that the path to the resource file test.csv would still be correct.
To keep things simple, I have used invalid Java API ( readAllLines() which reads all the lines and return a string containing entire file content. Also not using try/catch).
Assume csv file can be read as well as written to.
I hope this makes it clear now.
Put the test.csv file into the src folder and use this:
Foo.class.getResourceAsStream("/test.csv")
To get an InputStream for the file. This will work wherever the project is moved, including packaged as a JAR file.
Example:
ProjectX\src\Test.java
ProjectX\resources\config.properties
If you have the above structure and you want to use your config.properties file, this is how you do it:
InputStream input = new FileInputStream("./resources/config.projects");
In this example you don't have to worry about packaging your source into jar file. You can still modify your resources folder anytime.
Use getResource(), as shown here.

How to get a path to a resource/file out of a Java JAR file

I'm trying to get the path to a file that it is located out of the java jar and I don't want to use an absolute path. An exampel: lets say that the jar is located in ~/lib/myjar.jar and the file is located in the same folder. What I've trying is something like this, but it fails:
File myfile = new File(this.getClass().getResource("../../../").toURI());
Note: my package is com.contro.gui, that's why I have "../../../", in order to acces to the "root"
I'm not sure how I can access to the file. Any suggestion?? And what about if the file that I want to access is in other folder like ~/res/ ???
If the file is in the same directory as the jar, I think this will work (feels fairly hacky, but...):
URL url = getClass().getProtectionDomain().getCodeSource().getLocation();
File myfile = new File(url.toURI());
File dir = myfile.getParentFile(); // strip off .jar file
(Haven't tested this, but it seems feasible. Will only work with file-based jars of course).
If the file is in some random location, I think you will need to either pass in parameters or check "known" locations like user.home. (Or, you could always put the file in the jar a use getResource().)
No just do
File FileName = new File(".");
String Directory = FileName.getCanonicalPath();
that will get you the parent directory of your class in a file or jar just remember to set the directory if it's in a jar like this "NameOfJar\NameOfFolder\etc"

Categories

Resources