Why can my library not access its resources? - java

I have a class that reads a file:
package classlibrary;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
public class ReadingResource {
public static String readResource() throws IOException {
URL resource = ClassLoader.getSystemClassLoader().getResource("classlibrary/test_file.txt");
BufferedReader br = new BufferedReader(new FileReader(resource.getPath()));
return br.readLine();
}
}
The resource file is in the same directory where this class is.
I made a library out of this class and the file.
Now I want to use it in the other class:
package uritesting;
import classlibrary.ReadingResource;
import java.io.IOException;
public class URITesting {
public static void main(String[] args) throws IOException {
System.out.println(ReadingResource.readResource());
}
}
When I make a .jar file out of this class, set the class as the main class, add the .jar from above and execute it as "java -jar URITesting.jar" I get a FileNotFoundException, saying the class ReadingResource can not find the specified file. It is funny because the path that is specified in the exception message is actually the correct path to the file.
You can find the files here.
EDIT:
I developed the project in NetBeans. When I run it there, it works fine. The classpath is different in that case. It contains both resources of the URITestingProject and ReadingResource.
However, when I run it as a standalone JAR, the classpath contains URITestingProject only. What is strange to me is that it doesn't complain about not finding the class ReadingResource. It means that it is loaded, although it is not in the classpath :/

The problem is resource.getPath(). It's not possible to calculate a path ,valid for a file reader, inside a jar file, on another server and so on. However you can get the data through a stream instead:
InputStream data = ClassLoader.getSystemClassLoader().getResourceAsStream("classlibrary/test_file.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(data, "utf-8"));
As a side note: When reading with reader it's a good idea to specify the encoding:

Related

Cannot access Resource files in JavaFX 16 when module-info.java file exists

I just started using Java 16 and can't seem to figure out why I am unable to access resource files. I went through some troubleshooting to narrow down at least where I seem to be having a problem.
I'm using IntelliJ IDEA 2021.2 Build #IU-212.4746.92
I created a new project and I chose JavaFX with OpenJDK 16.
It then creates the project with three main files, an Application class, a Controller class, and a FXML file. Once I create the project, I go into the POM file and I chose version 16 of javaFX-controls and javafx-fxml and I tell it to get the latest version of the other libraries it adds automatically into the POM file.
I also copy two folders from a different project into the resources folder - all copy and pasting is done within IntelliJ.
When I run the application that it put there (called HellpApplication), it works fine. And that application uses class.getResource to grab the fxml file and again ... it works just fine. However, when I try to run this class:
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
public class FileResourcesUtils {
public static void main(String[] args) throws URISyntaxException {
FileResourcesUtils app = new FileResourcesUtils();
String fileName = "StyleSheets/AnchorPane.css";
System.out.println("getResourceAsStream : " + fileName);
InputStream is = app.getFileFromResourceAsStream(fileName);
printInputStream(is);
System.out.println("\ngetResource : " + fileName);
File file = app.getFileFromResource(fileName);
printFile(file);
}
private InputStream getFileFromResourceAsStream(String fileName) {
ClassLoader classLoader = getClass().getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(fileName);
if (inputStream == null) {
throw new IllegalArgumentException("file not found! " + fileName);
}
else return inputStream;
}
private File getFileFromResource(String fileName) throws URISyntaxException{
ClassLoader classLoader = getClass().getClassLoader();
URL resource = classLoader.getResource(fileName);
if (resource == null) {
throw new IllegalArgumentException("file not found! " + fileName);
}
else return new File(resource.toURI());}
private static void printInputStream(InputStream is) {
try (InputStreamReader streamReader =
new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(streamReader)
)
{
String line;
while ((line = reader.readLine()) != null) System.out.println(line);
}
catch (IOException e) {e.printStackTrace();}
}
private static void printFile(File file) {
List<String> lines;
try {
lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
lines.forEach(System.out::println);
}
catch (IOException e) {e.printStackTrace();}
}
}
It throws this error:
getResourceAsStream : StyleSheets/AnchorPane.css
Exception in thread "main" java.lang.IllegalArgumentException: file not found! StyleSheets/AnchorPane.css
at com.simtechdata.test/com.simtechdata.test.FileResourcesUtils.getFileFromResourceAsStream(FileResourcesUtils.java:27)
at com.simtechdata.test/com.simtechdata.test.FileResourcesUtils.main(FileResourcesUtils.java:16)
Then, THE ONLY THING I HAVE TO DO ... is DELETE module-info.java, then that class runs perfectly! HOWEVER, without module-info.java there, I cannot run any FX code...
Here is module-info.java:
module com.simtechdata.test {
requires javafx.controls;
requires javafx.fxml;
opens com.simtechdata.test to javafx.fxml;
exports com.simtechdata.test;
}
Why did I use this class? Because I'm having the exact same problem trying to access resource files in my JavaFX application and this class was the easiest way for me to demonstrate the problem and show that it is specifically connected to the module-info file. When I run my own JavaFX code, it works just fine, until I try to access a resource file like a style sheet to throw onto a control.
What I would like to know is ... what sort of magic trick do I need to do in order to be able to access resource files from my JavaFX 16 application? What am I missing?
I'vr tried all of these different ways of getting to the resource file, but each one gives the same error:
String CSS_ANCHOR_PANE = this.getClass().getResource("StyleSheets/AnchorPane.css").toExternalForm();
String CSS_ANCHOR_PANE = ClassName.getClass().getResource("StyleSheets/AnchorPane.css").toExternalForm();
ClassLoader resource = ClassLoader.getSystemClassLoader();
String CSS_ANCHOR_PANE = resource.getResource("StyleSheets/AnchorPane.css").toExternalForm();
Class<?> resource = this.getClass();
String CSS_ANCHOR_PANE = resource.getResource("StyleSheets/AnchorPane.css").toExternalForm();
And here is a screenshot of the resource folder tree:
Any ideas?
This question is really answered in numerous other places around the StackOverflow site, but I'll pull together various solutions here.
You basically have three options:
Use the getResource() (or getResourceAsStream(), though the former is slightly preferable) method defined in Class, instead of in ClassLoader with the correct path. This avoids any issues with modularity.
Make the project non-modular (i.e. don't define a module-info.java file) and specify the modules to be added as runtime parameters to the JVM. This allows you to use either ClassLoader's getResource() or Class's getResource() method.
Create a modular project and use ClassLoader's getResouce() method, and open the package containing the resource unconditionally.
Solution 1 is detailed here. Since the style sheet you are loading is in the StyleSheets package1, and the class you are loading it from appears (from the stack trace) to be in an unrelated package com.simtechdata.test, you should provide an absolute path:
String CSS_ANCHOR_PANE = this.getClass().getResource("/StyleSheets/AnchorPane.css").toExternalForm();
For solution 2, use
String CSS_ANCHOR_PANE = this.getClass().getClassLoader().getResource("StyleSheets/AnchorPane.css").toExternalForm();
Remove the module-info.java file, and run the application with the JVM arguments
--module-path="/path/to/javafx/modules" --add-modules="javafx.controls,javafx.fxml"
(Replace /path/to/javafx/modules with the actual file system path to the JavaFX modules. The javafx.fxml module is only required in the add-modules parameter if you are using FXML.)
For solution 3, use
String CSS_ANCHOR_PANE = this.getClass().getClassLoader().getResource("StyleSheets/AnchorPane.css").toExternalForm();
Since your resource is in the StyleSheets package1 you need to open that package unconditionally. Add the line
opens StyleSheets ;
to your module-info.java file. See https://stackoverflow.com/a/48790851/2189127
(1) It's very strongly advised to follow standard naming conventions; I'm not even sure if solution 3 will work with a non-standard package name (package names should be all lower-case).
You write a lot about JavaFX but instead you should concentrate on the real problem. As you have shown yourself via your test program this problem is a module system problem and not a JavaFX problem.
You can get rid of this problem by just not using the module system. Just wrap your main method into something like this:
class MyAppLauncher {public static void main(String[] args) {MyApp.main(args);}}
The assumption is that MyApp is your main class which extends Application. The use MyAppLauncher to start your JavaFX program and remove all module system related options.

File not found exception error in Java

I'm trying to read a file but I can't seem to make it work. It shows an error: "File not found exception". The system cannot find the file specified. I enclosed the code below. Can anyone solve this issue?
package trailfiledemo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
*
* #author VIGNESH
*/
public class Trailfiledemo {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws FileNotFoundException, IOException {
// TODO code application logic here
FileReader fr=new FileReader("C:\\Users\\VIGNESH\\Documents\\ga and pso\\hellodata.txt");
int i;
while((i=fr.read())!=-1)
System.out.print((char)i);
fr.close();
}
}
Check if your file exists within the designated file path as it needs to match. Another possibility that Joik mentioned above, is your compiler might not have permission to access the file within the path given. You could try an alternative file path if that is the case.
FileNotFound exception has wrong name. It may appear not only in case the file is absent, so there is an ambiguity.
There are three cases where a FileNotFoundException may be thrown:
1.The file does not exist.
2.The file is actually a directory.
3.The file cannot be opened. It may have no read access in your OS.
You need to check all 3 fail cases to be sure about the root of the issue. Documentation page contains some details:
https://docs.oracle.com/javase/7/docs/api/java/io/FileNotFoundException.html
I implemented your code and only changed your username to mine and it compiled like a charm. Read everything in the file and ended succesfully.
Try:
Click on Run > Clean and Build Project maybe it didn't take one of your changes.
Other things you might want to try:
use a buffered reader:
try (BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\VIGNESH\\Documents\\ga and pso\\hellodata.txt"))) {
String line;
while ((line = br.readLine()) != null)
System.out.print(line + "\n");
}
Or you could move the file into the same folder as the code and use this path '"src\stackoverflow\hellodata.txt"' stackoverflow => your packageĀ“s name

Java-Copy file.txt inside org which is a folder in A.jar without extracting z.jar file

I was trying to copy a file into a A.jar (without extracting it) but it didn't work. Suppose I have file "copy.txt" in "D:\java\copy.txt" and i want this file to be copied into my "A.jar/org/here" . if the file is already exist then it should replace it.
i tried modifying the below code but it didn't work.
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class deploy {
public static void main(String[] argv) {
Path myFilePath = Paths.get("C:/Users/ma329300/Desktop/copy.txt");
Path zipFilePath = Paths.get("D:/java/A.jar");
try( FileSystem fs = FileSystems.newFileSystem(zipFilePath, null) ){
Path fileInsideZipPath = fs.getPath("/org/copy.txt");
Files.copy(myFilePath, fileInsideZipPath);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
First of all, check your paths. Java is really tricky with the paths and should be in full path form.
Try putting the backslashes like "D:\java\A.jar", as windows works differently than linux.
Also, if you change your file and re-compile, it will generate a new .jar each time, with the updated file you wanted to change. That would solve your problem without having to access your .jar externally.
I tried once to access libraries packed on a .jar and load them with the code inside the .jar too and didn't worked propperly, so be carefull.
Another thing you should be aware of is that you cannot modify a .jar directly without decompressing, as it uses a special algorythm in order to get the indexation properly done for and by java. Changing one specific part of the .jar could corrupt the data into it and make it crash on the run.
Hope it helped.

How to build jar artifact so at run-time it will be able to read packed files?

At run-time application successfully files at project's root. All works fine when executing project in IntelliJ but when built jar artifact by IntelliJ executed in Windows environment it has troubles locating/reading files although they reside in root of jar file. How to fix it?
UPDATE
I am using Jersey framework. I read file from root path like that:
package example;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
#Path("/monitor")
public class MonitoringPage {
#GET
#Produces("text/html")
public String getMonitoringPage() throws IOException {
String page, line;
page = "";
BufferedReader br = new BufferedReader(new FileReader("MonitoringPage.htm"));
while((line = br.readLine()) != null){
page += line + "\r\n";
}
br.close();
return page;
}
}
My jar has MonitoringPage.htm in it's root but it cannot find it for some strange reason.
I am running jar with bat script:
java -jar "Rs.jar"
.
JAVA_HOME=C:\Program Files\Java\jdk1.7.0_51
Path=.......**C:\Program Files\Java\jdk1.7.0_51\bin**
Don't read it as a file from the file system (as is what happens when you use File, FileReader or many of its FileXxx variants). Once you package the jar, the file will no long be in the system file location you are expecting
Instead read it as a resource via an URL. You can use:
MonitoringPage.class.getResourceAsStream("/MonitoringPage.htm") which will return an InputStream.
From that InputStream you can just do something like
InputStream is = MonitoringPage.class.getResourceAsStream("/MonitoringPage.htm");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
Note: this is all assuming you have the file at the root of the classpath (which it looks like from your image). The / in the front of the path will bring the search to the root of the classpath. So just use the path to the file that's relative to the root

Java - FilenotfoundException for reading text file

by running this...
File file = new File("Highscores.scr");
i keep getting this error, and i really don't know how to get around it.
the file is currently sitting in my source packages with my .java files.
I can quite easily read the file by specifying the path but i intend to run this on multiple computers so i need the file to be portable with the program.
this question isnt about reading the text file but rather specifying its location without using an absolute path .
ive searched for the answer but the answers i get are just "specify the name" and "specify the absolute path".
id post an image to make it more clear but i dont have the 10 rep to do so :/
how do i do this?
cheers.
The best way to do this is to put it in your classpath then getResource()
package com.sandbox;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
public class Sandbox {
public static void main(String[] args) throws URISyntaxException, IOException {
new Sandbox().run();
}
private void run() throws URISyntaxException, IOException {
URL resource = Sandbox.class.getResource("/my.txt");
File file = new File(resource.toURI());
String s = FileUtils.readFileToString(file);
System.out.println(s);
}
}
I'm doing this because I'm assuming you need a File. But if you have an api which takes an InputStream instead, it's probably better to use getResourceAsStream instead.
Notice the path, /my.txt. That means, "get a file named my.txt that is in the root directory of the classpath". I'm sure you can read more about getResource and getResourceAsStream to learn more about how to do this. But the key thing here is that the classpath for the file will be the same for any computer you give the executable to (as long as you don't move the file around in your classpath).
BTW, if you get a null pointer exception on the line that does new File, that means that you haven't specified the correct classpath for the file.
As far as I remember the default directory with be the same as your project folder level. Put the file one level higher.
-Project/
----src/
----test/
-Highscores.scr
If you are building your code on your eclipse then you need to put your Highscores.scr to your project folder. Try that and check.
You can try to run the following sample program to check which is the current directory your program is picking up.
File f = new File(".");
System.out.println("Current Directory is: " + f.getAbsolutePath());

Categories