Paths for images and executables in a jar - java

I have created a java program in eclipse and I am now ready to export it as a jar. My program uses an image file and an executable file. When testing my program in eclipse I referred to these file with a full path, which I obviously cannot do for the jar. Therefore, I changed them like this:
public static final String DRIVERLOC = "./resources/IEDriverServer.exe";
//some other code
File file = new File(DRIVERLOC);
System.setProperty("webdriver.ie.driver", file.getAbsolutePath());
and
File pic = new File("./images/Open16.gif");
openButton = new JButton("Select the Text File", createImageIcon(pic.getAbsolutePath()));
I put the images and the resources and images directory in the same directory with the jar. Now for some reason when I run the jar the IEDriverServer works fine but the image does not work and the error is that it cannot find the image. I am confused since I cannot seems to tell the difference. I also used "images/Open16.gif" which did not work either. Why would one work but the other does not? What is the easiest way to fix this?

We do this exact same thing with Selenium Drivers.
What you need to do is take the executable file out of the jar and put it some where windows can run it. If you try and open a jar/zip in Windows Explorer and then double click the .exe inside of a jar/zip, windows will extract the file to a temp directory, and then run it. So do the same thing:
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class TestClass {
public static void main (String[] args) throws IOException {
InputStream exeInputStream = TestClass.class.getClassLoader().getResourceAsStream("resources/IEDriverServer.exe");
File tempFile = new File("./temp/IEDriverServer.exe");
OutputStream exeOutputStream = new FileOutputStream(tempFile);
IOUtils.copy(exeInputStream, exeOutputStream);
// ./temp/IEDriverServer.exe will be a usable file now.
System.setProperty("webdriver.ie.driver", tempFile.getAbsolutePath());
}
}
Let's say you save the jar and make it run this main function by default.
Running C:\code\> java -jar TestClass.jar Will run the jar from the C:\code directory. It will create the executable at C:\code\temp\IEDriverServer.exe

With your path set to "./resources/IEDriverServer.exe" you are referring to a file on the hard drive "." which does not exist.
You need to get the path of your .jar-file.
You can do this by using
System.getProperty("java.class.path")
This can return multiple values, seperated by semi-colons. The first one should be the folder your jar is in.
You can also use
<AnyClass>.class.getProtectionDomain().getCodeSource().getLocation()
I hope this helps :)
EDIT:
// First, retrieve the java.class.path property. It returns the location of all jars /
// folders (the one that contains your jar and the location of all dependencies)
// In my test it returend a string with several locations split by a semi-colon, so we
// split it and only take the first argument
String jarLocation = System.getProperty("java.class.path").split(";")[0];
// Then we want to add that path to your ressource location
public static final String DRIVERLOC = jarLocation + "/resources/IEDriverServer.exe";
//some other code
File file = new File(DRIVERLOC);
System.setProperty("webdriver.ie.driver", file.getAbsolutePath());
You can read about this here.

Related

Java File Reading: Have to enter full path

package files;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.io.File;
public class file {
public static void main(String[] args)throws FileNotFoundException {
File file = new File("txtfile.txt");
Scanner input = new Scanner(file);
while (input.hasNextLine()) {
System.out.println(input.nextLine());
}
}
}
Where it says file.txt I have to enter the full file path. All tutorials I watch do not have to do this.
Yeah! File file = new File("txtfile.txt"); txtfile.txt is a path to your file that you want to read. Provide the path where file is like "C:\Users\me\Desktop\txtfile.txt" if the file is not in the same directory where your java file is. After you compile the java file a .class file is created it that .class file is also created in the same folder it will work with.
File file = new File("txtfile.txt"); and you don't need to specify the full path.
If not you then you have to provide the absolute file path like above.
If you don't enter the path it won't compile and show error.
To set a path..
Open the command prompt and it show something like this
C:user>admin
You need to change it and point it your program saved location (use cd for change it)
Then type path="
And go to localdisc C: and open programfile->java->jdk->bin
Then save the path at above
Which is something like c:/programfile/java/jdk1. 0./bin
Save and copy it in front of path="c:/programfile/java/jdk1. 0./bin";
Then press enter
Then compile the program using javac filename. Java
And run using java filename

Java says "file does not exist" when using absolute path

I'm working on a very simple project that's supposed to open an image with the windows video player when run. However, I've encountered a problem. I want to have it be able to access the file "snp.jpg" with a relative file path, so it will work on computers other than my own. But, when I have it set to a absolute file path, it fails and tells me that "the file ... does not exist". Any Ideas?
import java.awt.Desktop;
import java.io.File;
public class openpic {
public static void main (String args[]) throws Exception
{
File f = new File ("C:\Users\charl\Desktop\Computer Science\JavaProjects\src\snp.png");
Desktop d = Desktop.getDesktop();
d.open(f);
System.out.println("imageviewer open;");
}
}
(Ops... fixing the answer, after I read the text above the code)
The relative path will start from the directory you run the program. Also called current working directory.
Also, as you are using Files, try to use the NIO API, with Path. Like:
Path filePath = Paths.get("./snp.png")
With this API, you can check the working directory using:
filePath.toAbsolutePath()
// just print it then, or check with a debugger
Also, be careful about the slashes.
When using Windows and this slash \, you need to make them double: \\.
Other option is to invert it: /.
Microsoft Windows syntax
import java.awt.Desktop;
import java.io.File;
public class openpic {
public static void main (String args[]) throws Exception
{
// Microsoft Windows syntax
File f = new File ("C:\\Users\\charl\\Desktop\\Computer Science\\JavaProjects\\src\\snp.png");
Desktop d = Desktop.getDesktop();
d.open(f);
System.out.println("imageviewer open;");
}
}

Getting the path of a running JAR file returns "rsrc:./"

My code runs inside a JAR file and I need to get the full path of that file.
For example, my JAR is called example.jar and is located at D:\example\
So I need to get "D:\example\example.jar" by some code inside that jar.
I have tried many methods to get that path, but none of them worked correctly.
One of them is
getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath()
Many people say that this works for them, but it returns "rsrc:./" for me.
I have searched after that and I noticed that my MANIFEST.MF contains this:
Manifest-Version: 1.0
Rsrc-Class-Path: ./
Class-Path: .
Rsrc-Main-Class: Example
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
I don't know what that means, but if I remove that Rsrc stuff and replace the other things with it, it says the jar is broken. I think this is the reason why it doesn't work. Does anybody know what this means?
PS: I'm running my JAR using a BAT file.
I stumbled over this problem too and leave my investigations here for people who ask themselves in the future what the rsrc means.
I'm using Eclipse Mars 1 and try to export my project as a runnable JAR. There I can choose the library handling and decide between:
Extract required libraries into generated JAR
Package required libraries into generated JAR
Copy required libraries into a sub-folder next to the generated JAR
The line to be tested is
System.out.println(MyClass.class.getProtectionDomain().getCodeSource().getLocation());
the JAR file's name is MyJar.jar (which will be put on desktop), Project's name and folder is MyProject.
Results:
file:/C:/Users/admin/Desktop/MyJar.jar
rsrc:./
file:/C:/Users/admin/Desktop/MyJar.jar
<means running in Eclipse> file:/C:/Development/workspace/MyProject/target/classes/
I wrote a convinience method for that:
public class SystemUtils {
/**
* Let no one instanciate this class.
*/
private SystemUtils() {}
/**
* If the current JVM was started from within a JAR file.
* #return <code>Boolean.TRUE</code> if it is, <code>Boolean.FALSE</code> if it is not, <code>null</code> if unknown.
*/
public static Boolean executedFromWithinJar() {
Boolean withinJar = null;
try {
String location = SystemUtils.class.getProtectionDomain().getCodeSource().getLocation().toString();
if (location.startsWith("rsrc:")
|| location.endsWith(".jar") && !new File(location.substring(location.indexOf(':') + 1)).isDirectory())
withinJar = Boolean.TRUE;
else
withinJar = Boolean.FALSE;
}
catch (Exception ex) {/* value is still null */}
return withinJar;
}
}
Based on your comments, it appears your real question is how to copy files from inside your application .jar. You can do that with something like this:
String jarEntry = "/files/data.txt";
Path destination = Paths.get(
System.getProperty("user.home"), "Downloads", "data.txt");
try (InputStream stream = getClass().getResourceAsStream(jarEntry)) {
Files.copy(stream, destination);
}
Class.getResource and Class.getResourceAsStream read data from the classpath, usually as an entry in a .jar file that is on the classpath, such as your own application’s .jar file.
A file embedded in the classpath is normally called an application resource or just “resource” for short. Resources are always specified using the forward slash (/) as a directory separator, on all platforms, even Windows.
If you are not sure what string you should pass to getResource or getResourceAsStream, examine the contents of your .jar file.
package com.example;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
public class HomeJar {
public static void main(String[] args) throws IOException {
URL u = HomeJar.class.getProtectionDomain().getCodeSource().getLocation();
File f = new File(u.getPath().toString());
if (!f.isFile()) {
throw new RuntimeException("'" + u + "' isn't a jar");
}
try (JarInputStream jis = new JarInputStream(new BufferedInputStream(new FileInputStream(f)))) {
JarEntry je = jis.getNextJarEntry();
while (je != null) {
System.out.println(je.getName());
je = jis.getNextJarEntry();
}
}
}
}
I just have created a new workspace and moved every project into it and everything works fine now, I think it was a bug or something...Thank you all for your help!
This was the exact problem I had today. I finally found this:
To get the jar-file location when packaging with eclipses Package required libraries into generated JAR one can use this (insert name of the calling class in the <>:
var thisClassesResourcePath = <CLASSNAME>.class.getName().replace('.', '/') + ".class";
var resource = ClassLoader.getSystemResource(thisClassesResourcePath);
var path = resource.getPath();
var jarUrl = new URL(path.substring(0, path.lastIndexOf("jar!") + 3));

Opening a PDF file stored in a jar file with the desktop's default app

I'm nearing the end of a program development for my computer science course. However, one of the requirements is to have a user manual within the app. I saved the user manual as a PDF inside Eclipse's workspace.
It is stored under "/Documents/PDF Manual.pdf". I originally used this code:
URL url = getClass().getResource( fileSeparator + "Documents" + fileSeparator + "PDF Manual.pdf");
//fileSeparator = '/' on mac, & '\\' on windows
File userManual = new File (url.toURI());
if (userManual.exists())
{
Desktop.getDesktop().open(userManual);
}
This works fine while running the project from eclipse, however URI returns a non hierarchical exception (as expected) when the program is exported to a jar file. I thought of playing around with url.toString(), using substring and replaceAll() to get rid of unwanted characters (%20 for the space), however this gave weird results and of course the code wouldn't work properly when it wasn't a jar file.
I looked at InputStream, however this is only used to read from a file and I cannot open the file using a desktop app.
Due to the process of submission, the pdf HAS to be saved inside the project folders.
Also, my code has to be platform independent (or at the very least, work on windows and mac) and thus manipulating file names becomes a lot more complicated. Any suggestions?
Edit:
After #SubOptimal 's help, this is the code I am now using:
String inputPdf = "Documents" + fileSeparator + "PDF Manual.pdf";
InputStream manualAsStream = getClass().getClassLoader().getResourceAsStream(inputPdf);
Path tempOutput = Files.createTempFile("TempManual", ".pdf");
tempOutput.toFile().deleteOnExit();
Files.copy(manualAsStream, tempOutput, StandardCopyOption.REPLACE_EXISTING);
File userManual = new File (tempOutput.toFile().getPath());
if (userManual.exists())
{
Desktop.getDesktop().open(userManual);
}
This works on mac. However, on windows manualAsStream is null for some unknown reason.
Full working example. Tested in Windows environment.
file structure
.\REPL.java
.\doc\manual.pdf
.\manifest.mf
REPL.java
package sub.optimal;
import java.io.InputStream;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.awt.Desktop;
public class REPL {
public static void main(String[] args) throws Exception {
String inputPdf = "doc/manual.pdf";
Path tempOutput = Files.createTempFile("TempManual", ".pdf");
tempOutput.toFile().deleteOnExit();
System.out.println("tempOutput: " + tempOutput);
try (InputStream is = REPL.class.getClassLoader().getResourceAsStream(inputPdf)) {
Files.copy(is, tempOutput, StandardCopyOption.REPLACE_EXISTING);
}
Desktop.getDesktop().open(tempOutput.toFile());
}
}
manifest.mf
Main-Class: sub.optimal.REPL
compile
javac -d . REPL.java
create JAR
mkdir dist\
jar cvfm dist/REPL.jar MANIFEST.MF sub/optimal/REPL.class doc/manual.pdf
execute JAR
cd dist\
java -jar REPL.jar
Use getResourceAsStream instead of getResource
To write in the temp directory use createTempFile

Why isn't java finding my file

Trying to learn how to read text files in Java. I have placed the text file within the same folder as IdealWeight.java. Am I missing something here?
IdealWeight.java
package idealweight;
import java.util.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class IdealWeight
{
public static void main(String[] args)
{
Scanner fileIn = null; //Initializes fileIn to empty
try
{
fileIn = new Scanner
(
new FileInputStream
("Weights.txt")
);
}
catch (FileNotFoundException e)
{
System.out.println("File not found!");
}
}
}
You could also put the file in the classpath and then do this:
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("Weights.txt");
Just another idea.
The java file IO system does not look for the file in the same directory as the class, but in the "default" directory for the application. Any application you run has a directory that it regards as its default, and that's where it would attempt to open this file. Try putting a full pathname to the file.
Or put the file you want to read in a directory, and run the application from that directory (in a terminal window) with "java IdealWeight".
You need to put Weights.txt in your working directory, not in the directory with the source file. If you're using Eclipse or a similar IDE, the this is probably the project root. As per this answer, you can use this snippet to get the full path to your working directory:
System.out.println("Working Directory = " + System.getProperty("user.dir"));
Check the result of running that command, and that should tell you where to put your text file. Once you have the text file in the right place then the code you posted should work fine.

Categories

Resources