Instancing a java.io.File to read a resource from classpath - java

Supposing that I've a project structure as follows:
+ src
---+ main
------+ java
------+ resources
How can I define a java.io.File instance that is able to read an xml from resources folder?

It depends on what your program's working directory is.
You can get your working directory at runtime via System.getProperty("user.dir");
Here's a link with more info
Once you've got that, create a relative filepath pointing to your resource folder.
For example, if your working directory is src, create a relative filepath like so:
new File(Paths.get("main","resources").toString());
There are weaknesses with this approach as the actual filepath you use may change when you deploy your application, but it should get you through some simple development.

No, use an InputStream, with the path starting under resources.
InputStream in = getClass().getResourceAsStrem("/.../...");
Or an URL
URL url = getClass().getResource("/.../...");
This way, if the application is packed in a jar (case sensitive names!) it works too. The URL in that case is:
"jar:file://... .jar!/.../..."
If you need the resource as file, for instance to write to, you will need to copy the resource as initial template to some directory outside the application, like System.getProperty("user.home").
Path temp = Files.createTempFile("pref", "suffix.dat");
Files.copy(getClass().getResourceAsStream(...), temp, StandardCopyOption.REPLACE_EXISTING);
File file = temp.toFile();
As #mjaggard commented, createTempFile creates an empty file,
so Files.copy will normally fail unless with option REPLACE_EXISTING.

Related

How can I access a css file located in my "src/main/resources" folder from my JSF controller at runtime

I need to be able to access my web application's css files, that are stored under src/main/resources/styles, from the backend java controller. I want to use them for creating PDF output with iText.
In other words, I want to do something like this:
CssFile cssFile1 = XMLWorkerHelper.getCSS(new FileInputStream("src/main/resources/styles/my.css"));
However, I'm clearly not going about this correctly, as I am receiving Exceptions like this:
java.io.FileNotFoundException: styles\standard.css (The system cannot find the path specified)
How can a retrieve these files in the controller?
I tried this, but it did not work, same error:
String rcp = econtext.getRequestContextPath();
CssFile cssFile1 = XMLWorkerHelper.getCSS(new FileInputStream(rcp + "src/main/resources/styles/my.css"));
The FileInputStream operates on the local disk file system and all relative paths are relative to the current working directory, which is the local disk file system folder which is been opened at exactly the moment the JVM is started. This is definitely not the root of src/main/resources folder.
Given that the /src/main/resources is recognizable as a Maven folder structure for root of classpath resources, then you just need to obtain it as classpath resource by ClassLoader#getResourceAsStream() instead.
InputStream input = getClass().getResourceAsStream("/styles/standard.css");
// ...
Or if the class is possibly packaged in a JAR loaded by a different classloader.
InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream("styles/standard.css");
// ...
See also:
getResourceAsStream() vs FileInputStream
Thats because the JSF is a web app.
Now move the styles/my.css to WEB-INF/styles/my.css this ensures the files your accessing within the controller are part of the WebApp
and now you can access the resource using
XMLWorkerHelper.class.getResourceAsStream("styles/my.css")

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.

proper file path of a text file to read

I want to manipulate a file in my java program.The file to read must be paralled to my src folder.
What should I give as file path?
An elaborated example might help. From your question, what I get is,
Source Path : /home/user/project1/src/
File Path : /home/user/project1/src/
If this is the case, then once you build the project, the file path is not going to remain the same. So if you say that relative path for the file to open remains the same in built code, then you can use Class.getResourceAsStream(String path) which returns you the InputStream for given file. You can then construct the File object using it.
Refer this for details.
You should have a File object representing your src folder, and then create a new File object using that:
File textFile = new File(srcFolder, relativePath);
How you determine srcFolder really depends on the context.
EDIT: If you're just trying to read a file which is present at build time, you should include it in your built jar file and use either ClassLoader.getResourceAsStream or Class.getResourceAsStream to load it at execution time.
For example, if you have this structure:
src\
com\
xyz\
Foo.class
data\
input.txt
Then you could use Foo.class.getResourceAsStream("/data/input.txt") or Foo.class.getClassLoader.getResourceAsStream("data/input.txt"). Both will give you an InputStream you can use to load the data.

Getting the absolute path of a file within a JAR within an EAR?

I have a J2EE app deployed as an EAR file, which in turn contains a JAR file for the business layer code (including some EJBs) and a WAR file for the web layer code. The EAR file is deployed to JBoss 3.2.5, which unpacks the EAR and WAR files, but not the JAR file (this is not the problem, it's just FYI).
One of the files within the JAR file is an MS Word template whose absolute path needs to be passed to some native MS Word code (using Jacob, FWIW).
The problem is that if I try to obtain the File like this (from within some code in the JAR file):
URL url = getClass().getResource("myTemplate.dot");
File file = new File(url.toURI()); // <= fails!
String absolutePath = file.getAbsolutePath();
// Pass the absolutePath to MS Word to be opened as a document
... then the java.io.File constructor throws the IllegalArgumentException "URI is not hierarchical". The URL and URI both have the same toString() output, namely:
jar:file:/G:/jboss/myapp/jboss/server/default/tmp/deploy/tmp29269myapp.ear-contents/myapp.jar!/my/package/myTemplate.dot
This much of the path is valid on the file system, but the rest is not (being internal to the JAR file):
G:/jboss/myapp/jboss/server/default/tmp/deploy/tmp29269myapp.ear-contents
What's the easiest way of getting the absolute path to this file?
My current solution is to copy the file to the server's temporary directory, then use the absolute path of the copy:
File tempDir = new File(System.getProperty("java.io.tmpdir"));
File temporaryFile = new File(tempDir, "templateCopy.dot");
InputStream templateStream = getClass().getResourceAsStream("myTemplate.dot");
IOUtils.copy(templateStream, new FileOutputStream(temporaryFile));
String absolutePath = temporaryFile.getAbsolutePath();
I'd prefer a solution that doesn't involve copying the file.
Unless the code or application you are passing the URI String to accepts a format that specifies a location within a jar/zip file, your solution of copying the file to a temporary location is probably the best one.
If these files are referenced often, you may want to cache the locations of the extract files and just verify their existance each time they are needed.
You should copy the contents to a temporary file (potentially with a cache), because trying to get to internal files of the application container is a dependency you want to avoid. There may not even be an extracted file at all (it can load from the JAR directly).

open resource with relative path in Java

In my Java app I need to get some files and directories.
This is the program structure:
./main.java
./package1/guiclass.java
./package1/resources/resourcesloader.java
./package1/resources/repository/modules/ -> this is the dir I need to get
./package1/resources/repository/SSL-Key/cert.jks -> this is the file I need to get
guiclass loads the resourcesloader class which will load my resources (directory and file).
As to the file, I tried
resourcesloader.class.getClass().getResource("repository/SSL-Key/cert.jks").toString()
in order to get the real path, but this way does not work.
I have no idea which path to use for the directory.
I had problems with using the getClass().getResource("filename.txt") method.
Upon reading the Java docs instructions, if your resource is not in the same package as the class you are trying to access the resource from, then you have to give it relative path starting with '/'. The recommended strategy is to put your resource files under a "resources" folder in the root directory. So for example if you have the structure:
src/main/com/mycompany/myapp
then you can add a resources folder as recommended by maven in:
src/main/resources
furthermore you can add subfolders in the resources folder
src/main/resources/textfiles
and say that your file is called myfile.txt so you have
src/main/resources/textfiles/myfile.txt
Now here is where the stupid path problem comes in. Say you have a class in your com.mycompany.myapp package, and you want to access the myfile.txt file from your resource folder. Some say you need to give the:
"/main/resources/textfiles/myfile.txt" path
or
"/resources/textfiles/myfile.txt"
both of these are wrong. After I ran mvn clean compile, the files and folders are copied in the:
myapp/target/classes
folder. But the resources folder is not there, just the folders in the resources folder. So you have:
myapp/target/classes/textfiles/myfile.txt
myapp/target/classes/com/mycompany/myapp/*
so the correct path to give to the getClass().getResource("") method is:
"/textfiles/myfile.txt"
here it is:
getClass().getResource("/textfiles/myfile.txt")
This will no longer return null, but will return your class.
It is strange to me, that the "resources" folder is not copied as well, but only the subfolders and files directly in the "resources" folder. It would seem logical to me that the "resources" folder would also be found under `"myapp/target/classes"
Supply the path relative to the classloader, not the class you're getting the loader from. For instance:
resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();
In the hopes of providing additional information for those who don't pick this up as quickly as others, I'd like to provide my scenario as it has a slightly different setup. My project was setup with the following directory structure (using Eclipse):
Project/
src/ // application source code
org/
myproject/
MyClass.java
test/ // unit tests
res/ // resources
images/ // PNG images for icons
my-image.png
xml/ // XSD files for validating XML files with JAXB
my-schema.xsd
conf/ // default .conf file for Log4j
log4j.conf
lib/ // libraries added to build-path via project settings
I was having issues loading my resources from the res directory. I wanted all my resources separate from my source code (simply for managment/organization purposes). So, what I had to do was add the res directory to the build-path and then access the resource via:
static final ClassLoader loader = MyClass.class.getClassLoader();
// in some function
loader.getResource("images/my-image.png");
loader.getResource("xml/my-schema.xsd");
loader.getResource("conf/log4j.conf");
NOTE: The / is omitted from the beginning of the resource string because I am using ClassLoader.getResource(String) instead of Class.getResource(String).
When you use 'getResource' on a Class, a relative path is resolved based on the package the Class is in. When you use 'getResource' on a ClassLoader, a relative path is resolved based on the root folder.
If you use an absolute path, both 'getResource' methods will start at the root folder.
#GianCarlo:
You can try calling System property user.dir that will give you root of your java project and then do append this path to your relative path for example:
String root = System.getProperty("user.dir");
String filepath = "/path/to/yourfile.txt"; // in case of Windows: "\\path \\to\\yourfile.txt
String abspath = root+filepath;
// using above path read your file into byte []
File file = new File(abspath);
FileInputStream fis = new FileInputStream(file);
byte []filebytes = new byte[(int)file.length()];
fis.read(filebytes);
For those using eclipse + maven. Say you try to access the file images/pic.jpg in src/main/resources. Doing it this way :
ClassLoader loader = MyClass.class.getClassLoader();
File file = new File(loader.getResource("images/pic.jpg").getFile());
is perfectly correct, but may result in a null pointer exception. Seems like eclipse doesn't recognize the folders in the maven directory structure as source folders right away. By removing and the src/main/resources folder from the project's source folders list and putting it back (project>properties>java build path> source>remove/add Folder), I was able to solve this.
resourcesloader.class.getClass()
Can be broken down to:
Class<resourcesloader> clazz = resourceloader.class;
Class<Class> classClass = clazz.getClass();
Which means you're trying to load the resource using a bootstrap class.
Instead you probably want something like:
resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()
If only javac warned about calling static methods on non-static contexts...
Doe the following work?
resourcesloader.class.getClass().getResource("/package1/resources/repository/SSL-Key/cert.jks")
Is there a reason you can't specify the full path including the package?
Going with the two answers as mentioned above. The first one
resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();
resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()
Should be one and same thing?
In Order to obtain real path to the file you can try this:
URL fileUrl = Resourceloader.class.getResource("resources/repository/SSL-Key/cert.jks");
String pathToClass = fileUrl.getPath;
Resourceloader is classname here.
"resources/repository/SSL-Key/cert.jks" is relative path to the file. If you had your guiclass in ./package1/java with rest of folder structure remaining, you would take "../resources/repository/SSL-Key/cert.jks" as relative path because of rules defining relative path.
This way you can read your file with BufferedReader. DO NOT USE THE STRING to identify the path to the file, because if you have spaces or some characters from not english alphabet in your path, you will get problems and the file will not be found.
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(fileUrl.openStream()));
I made a small modification on #jonathan.cone's one liner ( by adding .getFile() ) to avoid null pointer exception, and setting the path to data directory. Here's what worked for me :
String realmID = new java.util.Scanner(new java.io.File(RandomDataGenerator.class.getClassLoader().getResource("data/aa-qa-id.csv").getFile().toString())).next();
Use this:
resourcesloader.class.getClassLoader().getResource("/path/to/file").**getPath();**
One of the stable way to work across all OS would be toget System.getProperty("user.dir")
String filePath = System.getProperty("user.dir") + "/path/to/file.extension";
Path path = Paths.get(filePath);
if (Files.exists(path)) {
return true;
}

Categories

Resources