javapathgetresourceaudioinputstream

file not found or syntax incorrect when using Main.class.getResource("notification.wav").getFile()


I am trying to play a .wav file but having trouble doing so with a relative path function.

public class Main {

    public static void main(String[] args) {
        playSound();
    }

    public static void playSound() {
        try {
            File file = new File(Main.class.getResource("notification.wav").getFile());
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
            Clip clip = AudioSystem.getClip();
            clip.open(audioInputStream);
            clip.start();
        } catch(Exception ex) {
            System.out.println("Error playing sound.");
            ex.printStackTrace();
        }
    }
}

If I run the code above in IntelliJ, I receive the error:
java.io.FileNotFoundException: C:\Users\Dominik\Documents\IntelliJ%20Projects\nbbot\out\production\nbbot\com\company\notification.wav (The system cannot find the path specified)

If I run my built .jar application, I receive the error:
java.io.FileNotFoundException: file:\C:\Users\Dominik\Documents\IntelliJ%20Projects\nbbot\nbbot_jar\nbbot.jar!\com\company\notification.wav (The filename, directory name, or volume label syntax is incorrect) in Java?

The .wav file an the Main class, where I run the code snipped are in the same folder:
nbbot > src > com > company > Main.java; notification.wav

It's strange, because the paths are correct and there should be no problem to just read the file. I also tried Main.class.getClass().getResource("notification.wav").getFile(); and .getPath() but no luck either. If I just use new File("notification.wav") and put the .wav the project folder nbbot the audio plays as intendet, but only in the IDE.


Solution

  • Your plan is broken. resources aren't usually files. Calling .getFile() on a resource is usually going to get you broken code. For example, when pack up your app into a jar, boom, breaks. a java.io.File object can only represent an actual file.

    Just about every API also lets you pass a URL or an InputStream instead of a File, use those - those are abstractions that apply to all resources.

    getAudioInputStream is just such a method, fortunately. It has overrides for em. Write this:

    try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(
      Main.class.getResource("notification.wav"))) {
    
      Clip clip = AudioSystem.getClip();
      clip.open(audioInputStream);
      clip.start();
    }
    

    This will probably fix this problem and will definitely mean that your code will continue to work once your files are packed up into a jar.

    NB: InputStreams are resources that must be closed, hence, you need to use try-with-resources, or your app will eventually hard-crash due to running out of OS handles after playing enough audio.