Access to resource missing with an exported jar file - java

If I run the following code within eclipse my program compiles with no issue. If I try to export the program as a runnable jar file my resource cannot be found.
public class Test {
public static void main(String[] args) {
File file = new File(Tester.class.getClassLoader().getResource("res/myFile.txt").getFile());
if(!file.exists()) { System.out.println("File not found."); }
}
}
Folder structure (by running jar tf test.jar):
com/
com/test/
com/test/Tester.class
res/
res/myFile.txt

There is no such file in case of jar.
Use instead Tester.class.getResourceAsStream("/myFile.txt") and work with the stream
UPDATE:
See more here or here

Related

Spring MVC - unable to access a file at a relative path required by JAR dependency

I am working on building a web application around a Standalone JAR application. Essentially the JAR application reads an input file, processes it and generates an output file.
The input file is placed like this, right next to the JAR.
The code for the JAR application is shown below.
public class FileReadWriteApp {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
File inFiles = new File("../inputFiles");
if (!inFiles.exists()) {
if (inFiles.mkdirs()) {
System.out.println("Input directory is created!");
} else {
System.out.println("Failed to create input directory!");
}
}
Path inputPath = FileSystems.getDefault().getPath("testInput.txt", new String[0]);
Files.copy(inputPath, new FileOutputStream("../inputFiles/testInput.txt"));
String content = new String(Files.readAllBytes(inputPath));
String parsedInput = content.toUpperCase();
new File("../outputFiles").mkdirs();
Files.write(Paths.get("../outputFiles/testOutput.txt"), parsedInput.getBytes());
} catch (IOException exc) {
System.out.println(exc);
System.exit(1);
}
}
Upon executing the JAR in the Command prompt it successfully creates inputFiles and outputFiles folders at one level higher than the JAR file and puts the corresponding input/output files correctly.
However, when I add the JAR as a dependency in the Spring based web application that I am building and place the input file and JAR file at the same location, it can't access the input file.
In the Spring web application I have placed both the input file and the JAR file as shown below:
I can even see them come up in the Target folder in the lib directory as shown below:
In my Spring Controller method, I am executing the main() method of the JAR file like this:
String[] args = new String[] { "" };
filereadwriteapp.FileReadWriteApp.main(args);
However, in the console I see these messages:
Input directory is created!
java.nio.file.NoSuchFileException: testInput.txt
I am not able to understand why the application can't find the file testInput.txt?
Can somebody kindly guide me regarding fixing this issue?
Is there some specific location where I should place the testInput.txt file so that the "dependency" JAR file can access it?
Kindly note that I am not loading a resource from WEB-INF directory from within the Web Application. In my case, I am having issue with a "dependency" JAR loading a resource from a relative path to itself.
Any help in this regard would be highly appreciated.
FileSystems api returns different path , so you need to use classpath to get the file as shown below
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("testInput.txt").getFile());

the print of getAbsolutePath in Java

My development environment: Mac + IntelliJ Idea.
I'm practicing the File class in Java.
public class FileDemo {
public static void main(String[] args) throws IOException {
File file = new File("/Users/Samuel/IdeaProjects/JavaFundamentals/src/aa/bb/test.txt");
file.createNewFile();
System.out.println(file.getAbsolutePath());
}
}
the result is /Users/Samuel/IdeaProjects/JavaFundamentals/src/aa/bb/test.txt
It's OK.But after I changed the path,the print became strange.
public class FileDemo {
public static void main(String[] args) throws IOException {
File file = new File("test.txt"); //notice this line
file.createNewFile();
System.out.println(file.getAbsolutePath());
}
}
the print is /Users/Samuel/IdeaProjects/test.txt
I'm confused of the path.
Because "test.txt" is a relative path and the file will be created relative to the program's working directory (in this case /Users/Samuel/IdeaProjects/).
In the first case you have provided the full path in your initialization. So it is printing the full path. In the second case, you are using relative paths. The base path for that is home directory of your project.
1) When you provide the full path in File class constructor while creating the File object then it will create the file on mentioned path.
2) But In case you are not providing the full path then it will create the File on the same path where your .class file is. It is relative path.
Your project folder is the main folder for the File class. This is where the File class starts from. If you want a lower folder you need te specify your path or you can use: "new File("../");
The main reason why it is in the folder "IdealProjects" is, because this is the start path of your project.

How to test a function that copies a folder out of its own JAR file?

I have a function (see below) that copies all files of a specific folder from its own JAR.
For this function (see below too), I want to write tests, but the tests will be executed before the JAR is builded (it's a maven project) .
One important part of this function is that it only knows the folder name, but not the files in this folder so it must "query" for them.
The problem is, that the APIs to "query" for all files of one folder differ whether they work on a JAR (production) or on the file system (test).
My question is:
How to test the function that relay on the not yet existing JAR,
or how to "combine" the functions (how to decide whether it must the JAR or non JAR way),
or (that would be the best) is there any (small lib) that handle this subject?
The first method used for the jar. (production)
This is a little bit modified version of an answer to Copy directory from a jar file:
public class RessourcesUtil {
...
public static void copyResourcesFromJar((String nameOfResourceDirectory,
File destinationDirectory) throws IOException {
String jarPath = RessourcesUtil.class.getProtectionDomain().getCodeSource().
getLocation().getFile();
Enumeration<JarEntry> jarEntries = new JarFile(jarPath).entries();
while (jarEntries.hasMoreElements()) {
JarEntry fileFromJar = (JarEntry) jarEntries.nextElement();
if (fileFromJar.getName().startsWith(nameOfJarDirectory)) {
String plainFileName = fileFromJar.getName().
replaceAll(nameOfJarDirectory, "");
File fileToCreate =
new File(destinationDirectory + File.separator + plainFileName);
if (fileFromJar.isDirectory()) {
fileToCreate.mkdir();
continue;
}
createFile(jarFile.getInputStream(fileFromJar), fileToCreate);
}
}
}
private static void createFile(InputStream inputStream,
File fileToWrite) throws IOException {
try (FileOutputStream fos = new FileOutputStream(fileToWrite)) {
IOUtils.copy(inputStream, fos);
}
}
}
Second if the resources are not packed in a jar (for testing):
public class RessourcesUtil {
public static void copyResourcesFromFileSystem(String nameOfResourceDirectory,
File destinationDirectory) throws IOException {
String classDir = RessourcesUtil.class.getProtectionDomain().getCodeSource().
getLocation().getPath();
File srcDir = new File(classDir + File.separator + nameOfResourceDirectory);
FileUtils.copyDirectory(new File(srcDir.getPath()), destinationDirectory);
}
...
}
Both are working, but only under the circumstance of packed or unpacked.
Background:
For a project I wrote a multimodul Maven-plugin in Eclipse that can also be used as a standalone.
My resources are in a different modul than my main or my mojo.
Now I need to copy the a specific folder in resources, from my project into a different folder in every run.
P.S.
Copying every single file from resources via getResourcesAsStream is not an option.
Try this approach,
Have your maven build as two parts
first part being exclude the folder which you want to copy the files, so once this part is completed you will have your jars ready
second part execute your copying code which takes the input from the jar and moves it to the specified different folder.

File found in eclipse but not when I run the .jar in terminal

I have a program which has to play sounds from a terminal interface.
The code is fairly simple and here it is :
public static synchronized void playSound() {
new Thread(new Runnable() {
public void run() {
File _file = new File("music/sound.wav");
try (AudioInputStream _audio = AudioSystem
.getAudioInputStream(_file)) {
Clip _clip = AudioSystem.getClip();
_clip.open(_audio);
_clip.start();
} catch ([…] e) {
// […]
}
}
}).start();
}
The file is in the music folder which is in my source path.
All work perfectly well when I run the program in eclipse. But if I export it in a .jar file and try it in the windows cmd I get this message :
java.io.FileNotFoundException: music\sound.wav (The system cannot find the path specified)
[edit] The audio files are indeed packed into the .jar, but it still doesn’t work.
Is it even possible to play a sound from the windows prompt? If not, is there one that does?
Thanks,
SilverDuck
When the file is packaged into a jar file, it is no longer a File. It needs to be read as a resource. Try changing the code like this
InputStream inputStream = this.getClass().getResourceAsStream("music/sound.wav");
try (AudioInputStream _audio = AudioSystem.getAudioInputStream(inputStream)) {
Try either not packaging your music in jar (put it alongside) or load your packaged file as a resource.
See Java resource files for example.
Here Loading resources (images) contained in a .Jar file or in the classpath might be a better explanation.

How to scan an a txt within the same package?

I am trying to use Java.util.scanner on a txt to parse it. I am having trouble trying to scan the file because the file isn't found.
My class is within the same package of the txt file. So can you please tell me how to scan a file within the same package of the class.
public class PhoneBook {
private ArrayList<PhoneBookEntry>[] buckets;
public void load() {
try {
Scanner scan = new Scanner(new File("phone.txt"));
} catch (FileNotFoundException e) {
System.out.println("File Not Found");
}
}
public static void main(String[]args) {
PhoneBook phone = new PhoneBook();
phone.load();
}
}
Here is the StackTrace of the error
java.io.FileNotFoundException: phone.txt (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at java.util.Scanner.<init>(Unknown Source)
at HashSet.PhoneBook.load(PhoneBook.java:13)
at HashSet.PhoneBook.main(PhoneBook.java:23)
Put the file in the root of your class path (after compilation, your file should appear in the root folder where .class files are generated) and use the code syntax below:
InputStream is = getClass().getClassLoader().getResourceAsStream("phone.txt");
Scanner fileScanner = new Scanner(is);
new File("phone.txt")
looks up the file in the current working directory. This is the directory where you started the java virtual machine.
You say that it is located in the same package as the class, which is most likely a different directory (e.g. src/com/mypackage).
Try moving the file to the root directory of your project. You should then be able to load it.
A different approach is shown in the answer from #Yogendra, which should work also when the file is located in the same package binary directory as your .class file. But I am not sure if you want to load this kind of file as a resource.
As stated in one of the comments, you need to put the file where the .jar is generated. If you're running from Netbeans/Eclipse, this will be the root folder of your project, if you're running from the compiled .jar, it will be the same directory as the .jar. Packages are only folders used to organise and separate source files.
But if you want to have the file in the same package anyway, you can always do something like (presuming you only have one package):
new File("./src/myPackage/myFile.txt")

Categories