This question already has answers here:
Java resource as File
(6 answers)
Closed 9 years ago.
I have a jar file, say archive1.jar, resides in /home/ext/libs. This has a couple of classes, and also a text file (data.txt) at the root of the hierarchy of the jar. One of the classes of this jar (say Data.java) reads the file to initiate some internal data structure.
Now, the archive1.jar is included as a library of another program, called Parsing, which is executed in a completely different directory /home/progs (archive1.jar is specified in the classpath of the execution command of the program).
The problem I am facing is that now Data.java cannot understand the path of data.txt anymore, because it assumes that data.txt resides in /home/progs instead of being inside archive1.jar in /home/ext/libs.
My question is what change should I make inside Data.java in order for it to understand that the data.txt is inside the archive1.jar? In short, how to make Data.java be able to read data.txt inside archive1.jar, no matter where the calling program is.
Note: In thread Java resource as file, thing was a bit different, and also there was no answer to how to read the file inside the jar. One said it might be impossible.
The way to access resource files inside JAR archives is by using getClass().getResourceAsStream() . Using this ensures that the resource is loaded from the archive not from the filesystem. For example if you have data.txt in the same location as Data.java within the JAR archive, then you would access the data.txt in this way
InputStream is=getClass().getResourceAsStream("data.txt");
Once you have got an InputStream to the resource proceed with the way you like.
Related
This question already has answers here:
How to list the files inside a JAR file?
(17 answers)
Closed 1 year ago.
This method does not apply:
Files.walk(Paths.get("folder name"))
Because when the app is running, packaged as a jar, it does not contain File objects.
Is there a method for an app to walk through all the contents of one of its packages while it runs?
There is; open the jar file (using java.io.JarFile) and walk through the entries returned by entries(). There's also JarInputStream if your jar is being streamed in from elsewhere.
But, it sounds like you have equated 'jar file' with 'my application, at runtime'.
That's a tricky move. For starters, figuring out your own jar is possible but a little hacky, and more importantly, it then means your app straight up fails to work unless it is in jar form. This complicates deployment, development, and debugging.
There is no need to do it this way.
You can ask java for resources from 'whereever it is currently picking up class files'. A class file is a resource crucial to the running of your application. So is e.g. an icon file for a GUI app. Both should be coming from the same place, and where that is? That's abstracted away, and you should follow along with the abstraction, so that the 'load resource' code works just as well in debugging as it does at runtime.
The system for this is MyClass.class.getResource("file.txt") which will look for file.txt in the same place MyClass.class is located, even if it is in jar files, generated live, or obtained from a BLOB object in a database someplace, or streamed over a network.
The downside is, this system does not have an abstraction for listing files. Only for getting resources with a specific name.
The SPI system is the solution: Make a file that lists (one resource per line) the resources - instead of 'list dir', you 'parse each line of CONTENTS.txt' for the equivalent operation. You can then use annotation processors, if you must, to automatically create and maintain this content file.
ServiceLoader is baked into the JDK itself, but it's designed to load, specifically, class files and not other resources. But the principle is trivial and can be handwritten in about 5 lines of code.
You can iterate the contents of any ZIP / JAR file using Files / NIO, but you need to access the ZIP filesystem. Then you can call Files.find or Files.walk on the contents of the ZIP / JAR archive.
For example this will print the contents of every Path in a jar:
Path zip = Path.of("your.jar");
BiPredicate<Path, BasicFileAttributes> predicate = (p,a) -> true;
try (FileSystem fs = FileSystems.newFileSystem(zip)) {
for (Path root : fs.getRootDirectories()) {
try(Stream<Path> stream = Files.find(root, Integer.MAX_VALUE, predicate)) {
stream.forEach(System.out::println);
}
}
}
Once you have a Path object from the ZIP FileSystem, you can access the contents of the entries using NIO Files calls in the normal manner such as with Files.newInputStream or Files.copy.
This question already has answers here:
How to read text file from classpath in Java?
(17 answers)
Closed 3 years ago.
I want to read the configuration file outside the jar, how should I do?
I tried classloader.getResourceAsStream("config.xml") and succeeded while I am running the code inside Intellij. Now I want to build the jars to a folder and place the config.xml under the same folder, not inside the jar, but the program fails to detect the config.xml.
Is there a graceful way of reading the config.xml instead of using File with relative path in the code, which doesn't work while debugging/running inside the IDE?
Yes, turn it into a system property, and provide it to anything running any Java process/application.
Let's say you have a config.xml file located inside /some/path/down/the/line/, then you can do: java --classpath ... -Dapp.config=/some/path/down/the/line/config.xml tld.domain.Application.
Then all you have to do in your Java code is to reference that name/path: final String configFile = System.getProperty("app.config");, and use any well-known routine to read it from there.
Basically, you have to make sure the file/path/location is provided somehow to the Java classpath.
This question already has answers here:
How to get the current working directory in Java?
(26 answers)
Closed 3 years ago.
Part of my (java) code needs to access a database. When opening a connection it checks if the actual database file exists (I use sqlite). I want to make my code portable, so I want to avoid hard coding the path of the database file. Is there anyway in java to get the path of the .java file? Because I know exactly where the database is from the .java file accessing it.
I've tried using current directory with File but it doesn't give me the path of the actual .java file. When I use android studio the current directory is different than when I simply use a terminal.
The best way to get the path information would be using Paths and Path class from the java.nio. You can input an absolute path or relative path to the Paths.get(String str) to get the Path.
To get the project directory, you can use:
Paths.get(System.getProperty(“user.dir”))
Paths.get(“”)
It will get the complete absolute path from where your application was initialized.
The Paths.get() method will return a Path Object, on which you can call toString() or toUri() to get the path. Hope this helps.
Javadocs - Paths
This question already has answers here:
How to load JAR files dynamically at Runtime?
(20 answers)
Closed 4 years ago.
How to read a .class File located either in Local or Distributed File system to a Class object in Java?
I have a hello.class File in the local file system and in some cases it is in Distributed File System. I have a new application where I want to read the external hello.class file and construct a java.lang.Class object how do I do that?
Note: My hello.class is not in the class path of my Application and I still want to read just like I would read some external text file but I want to construct a java.lang.Class object?
You can use a decomplier like JAD or jd-gui
I have a library which is used by a program. This library loads a special directory in the resources folder.
in the library I have the method
public class DataRegistry{
public static File getSpecialDirectory(){
String resourceName = Thread.currentThread().getContextClassLoader().getResource("data").getFile().replace("%20", " ");
File file = new File(resourceName);
return file;
}
}
in my program I have the main method
public static void main(String args[]){
System.out.println(Data.getSpecialDirectory());
}
When I execute the getSpecialDirectory() in a junit test within the data program, the resource is fetched and all is well.
When I execute the getSpecialDirectory() in the main method outside the data program (imported jar) I get the jars data directory and not the directory the program executing the thread is expecting.
I figured getting the parent class loader would have solved this issue... I believe I may have a fundamental issue in my understanding here.
For clarity:
(library)
Line 15 of this file: https://gist.github.com/AnthonyClink/11275442
(Usage)
Line 31 of this file:
https://gist.github.com/AnthonyClink/11275661
My poms may have something to do with it, so sharing them is probably important:\
(Library)
https://github.com/Clinkworks/Neptical/blob/master/pom.xml
(Usage)
https://github.com/Clinkworks/Neptical-Maven-Plugin/blob/master/pom.xml
Maven uses the target/classes and target/test-classes directories to compose the classpath used to run unit tests. The content of your src/main/resources and src/test/resources gets copied to these locations together with the compiled java sources (the .class files).
java.lang.ClassLoader.getResource returns a java.net.URL.
In the unit test situation, ClassLoader.getResource returns a file:// schemed URL, and your code works as expected.
When your code is executed when packaged in a jar file, ClassLoader.getResource no longer returns a file:// schemed URL. It can't because the resource is no longer a separate entity in a file system - it's buried inside the jar file. What you actually get is a jar:file:// schemed URL.
jar: URLs cannot be accessed through a [java.io.File] object.
If you only need to read the content of the resource you should use java.lang.ClassLoader.getResourceAsStream(...) and read the content from that.
Note that it is not possible to update the content of class loader resources.
Do you want the directory where the Java program was loaded from ? Can try
File f = new File(".").getCanconicalFile();
Or if you want all the places could try parsing the classpath from System.env or use the default class loader
If you want a directory relative to the jar from where your classes were loaded: Quoting from http://www.nakov.com/blog/2008/06/11/finding-the-directory-where-your-java-class-file-is-loaded-from/
URL classesRootDir = getClass().getProtectionDomain().getCodeSource().getLocation();
The above returns the base directory used when loading your .class
files. It does not contain the package. It contains the classpath
directory only. For example, in a console application the above
returns someting like this:
file:/C:/Documents%20and%20Settings/Administrator/workspace/TestPrj/bin/
In a Web application it returns someting like this:
file:/C:/Tomcat/webapps/MyApp/WEB-INF/classes/
FYI This might apply if the user id running program cannot read all folders: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getProtectionDomain%28%29
or pass a .class object of the calling class as a parameter and get its classloader
There is no guarantee that you have a directory for your resources as far as I know. Java provide methods to get a resource as a InputStream, but nothing that can easily get the File for a resource, although it is possible to get the URL for a given resource.
If you need a special working directory in your application, I recommend having that passed as a system property, a program parameter, a web application parameter, or something else that lets you know where your application files are. You can even populate this directory with a ZIP file that you include as a resource in your application, as the ZIP libraries in Java do accept input streams as parameters.
While user #tgkprog is right and his answer correct, I can hardly imagine that you really want what you seem to have asked for and what he correctly answered in (3). Please edit your question and explain
what the output should look like if resourceName would be printed to the console,
if you really want the JAR file's location (in my test case that would be something like file:/C:/Users/Alexander/.m2/repository/com/clinkworks/neptical/0.0.1-SNAPSHOT/data, which does not make sense because you do not want to read from or even write to the local Maven cache),
or if you maybe rather want to read a resource directly from the JAR file or any other location such as the current working directory etc.
Otherwise I am afraid there is no good way to answer the question.