I use eclipse to do my java programming, last day i created a java program and i placed the /res folder to the root directory of the project, When i tested the program on eclipse it worked perfectly, but when i create an executable .jar file and i tried to run, I get the exception:
java.io.FileNotFoundException: res/music.wav (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:152)
at java.desktop/com.sun.media.sound.SunFileReader.getAudioInputStream(SunFileReader.java:117)
at java.desktop/javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1060)
at main.MusicPlayer.run(MusicPlayer.java:21)
at java.base/java.lang.Thread.run(Thread.java:1583)
It throws a FileNotFoundException but only when I run it as a .jar file. I saw that the jar file includes only the src/ folder so that's why it doesen't work. I tell someone and he told me that the res/ folder must be inside of ROOT directory. Can someone tell me how can i create a .jar file ? Where do i place the res/ folder ?
Also this is the code I use:
package main;
import java.io.File;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class MusicPlayer implements Runnable {
private float volume = 0.3f;
@Override
public void run() {
try {
// InputStream is = getClass().getResourceAsStream("/res/music.wav");
// BufferedInputStream bis = new BufferedInputStream(is);
File bis = new File("res/music.wav");
AudioInputStream ais = AudioSystem.getAudioInputStream(bis);
AudioFormat format = ais.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
int nBytesRead = 0;
byte[] abData = new byte[128000];
while (nBytesRead != -1) {
nBytesRead = ais.read(abData, 0, abData.length);
if (nBytesRead >= 0) {
for (int i = 0; i < nBytesRead; i++) {
// Scale the sample by the volume factor
abData[i] = (byte) (abData[i] * volume);
}
line.write(abData, 0, nBytesRead);
}
}
line.drain();
line.close();
ais.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
And This is the Main.java file:
package main;
public class Main {
public Main () {
Thread musicThread = new Thread(new MusicPlayer());
musicThread.start();
}
public static void main (String[] args) {
new Main();
}
}
There is nothing wrong with your program, you just need to confirm the directory structure.
Change back to your original InputStream writing method here.
@Override
public void run() {
try {
InputStream is = getClass().getResourceAsStream("/res/music.wav");
BufferedInputStream bis = new BufferedInputStream(is);
//File bis = new File("music.wav");
AudioInputStream ais = AudioSystem.getAudioInputStream(bis);
It should be noted that an additional resources
directory is created here, its type is Source Code. (New
-> Source Folder
)
Eclipse Menu: File
-> Export
demo1.jar
├── main
│ ├── Main.class
│ └── MusicPlayer.class
├── META-INF
│ └── MANIFEST.MF
└── res
└── music.wav
Check MANIFEST.MF
Manifest-Version: 1.0
Main-Class: main.Main
Class-Path: .
java -jar demo1.jar
eclipse_WK/TMP1
├── bin
│ ├── main
│ │ ├── Main.class
│ │ └── MusicPlayer.class
│ └── res
│ └── music.wav
├── resources
│ └── res
│ └── music.wav
└── src
└── main
├── Main.java
└── MusicPlayer.java
When Eclipse executes your program code, it will compile it first, and then put the result in the bin directory. It will compile
yyy.properties
or zzz.png
, aaa.wav
in the Source Folder directory to the bin directory.AAA
, and type is Source Folder
. But the usual name is resources
.classpath
in your Eclipse project directory, its contents:<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="resources"/>
<classpathentry kind="output" path="bin"/>
</classpath>
As you can see, there are two Source Folders
:
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="resources"/>
There is also an Output Folder
:
<classpathentry kind="output" path="bin"/>
├── bin
│ ├── main
│ │ ├── Main.class
│ │ └── MusicPlayer.class
│ └── res
│ └── music.wav
Here you can see the structure of the bin
directory. In fact, it is just like preparing your own directory on the command line. You can execute it without packaging it into a jar.
You can do this:
cd bin
java -cp . main.Main
Note 1: that here is -cp .
which is equivalent to the Class-Path: .
of MANIFEST.MF
in the Jar file.
Note 2: When Eclipse executes your Java, it is equivalent to manually executing the contents of the bin directory in Terminal. It will not be packaged into a jar file first.
Note 2 is the answer to the question in your comments.
Your comments:
so i think eclipse ide extracts only resources placed inside of resource directories in the .jar file...
You can find that the directory structure in the bin directory and jar is the same.
demo1.jar
├── main
│ ├── Main.class
│ └── MusicPlayer.class
├── META-INF
│ └── MANIFEST.MF
└── res
└── music.wav
META-INF/MANIFEST.MF
is automatically generated by Eclipse when you export as a Runnable JAR file
.
The newer approach is to use Maven
or Gradle
projects.
TMP2
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── example
│ ├── Main.java
│ └── MusicPlayer.java
└── resources
└── res
└── music.wav
The directory name main
will be used in Maven or Gradle. To avoid misunderstanding, do not use main
as the package name.
Main.java
and MusicPlayer.java
need to be modified: package com.example;
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>music-player</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>music-player</name>
<description>Music Player Project</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
mvn clean package
java -jar target/app.jar
Eclipse supports Maven projects.
Eclipse Menu: File
-> Import
-> Maven
-> Existing Maven Projects