Search code examples
javaswingintellij-idea

FileNotFoundException thrown only for .mp3s but not for .png


I'm developing a game in Swing, where I'd like to use both audio and image assets. My issue is that, while opening the .png images works fine, opening my .mp3 file always throws a FileNotFoundException, and file.exists() returns false.

Nothing seems to work. I've researched the issue, looked at a similar question, played around with adding and removing the '/' from the filePath, changing the mp3 directory, created a new IntelliJ project, restarted my PC, and tried opening a .wav file instead, with no success.

Here's a simplified version of my code, where I try to read an image Baker.png successfully, and read an audio file QuestOfLegends.mp3 unsuccessfully.

Main.java

import javax.imageio.ImageIO;
import javax.sound.sampled.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Objects;

public class Main {
    public static void main(String[] args) {
        String imagePath = "/images/Baker.png";
        String audioPath = "/audio/QuestOfLegends.mp3";

        System.out.println("The absolute path of this class is: " + new File(".").getAbsolutePath());
        System.out.println("The audio package is a directory?: " + new File("/audio").isDirectory());
        System.out.println("The images package is a directory?: " + new File("/images").isDirectory());

        try {
            BufferedImage image = ImageIO.read(Objects.requireNonNull(Main.class.getResource(imagePath)));
            System.out.println("Image read successful.");
        } catch (IOException e) {
            System.out.println("Image read failed.");
        }
        try {
            File file = new File(audioPath);
            if (!file.exists()) {
                throw new Exception("File does not exit at "+ audioPath);
            } else {
                AudioInputStream audioInput = AudioSystem.getAudioInputStream(file);
                Clip clip = AudioSystem.getClip();
                clip.open(audioInput);
                clip.start();
                clip.loop(Clip.LOOP_CONTINUOUSLY);
            }
        } catch (Exception e) {
            System.out.println("Read failed");
            throw new RuntimeException(e);
        }
    }
}

Here's my directory hierarchy.

I tried using:

File file = new File(Main.class.getResource("/audio/QuestOfLegends.mp3")); 

and I still got the same error.


Solution

  • Using File file = new File(Main.class.getResource("/audio/QuestOfLegends.mp3")); is wrong! It should be

    InputStream in = Main.class.getResourceAsStream("/audio/QuestOfLegends.mp3");
    

    Resources are deployed along with your app, generally inside a jar, so they are no longer files in the file system.

    The below illustrates this, plus some additional observations on the original code:

    import javax.imageio.ImageIO;
    import javax.sound.sampled.*;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.InputStream;
    import java.io.IOException;
    import java.util.Objects;
    
    public class Main {
        public static void main(String[] args) {
            String imagePath = "/images/Baker.png";
            String audioPath = "/audio/QuestOfLegends.wav"; // MP3 is not supported out of the box
    
            System.out.println("The absolute path of this class is: " + "Wherever it was compiled to");
            System.out.println("The audio package is a directory?: " + "No - it's a resource folder");
            System.out.println("The images package is a directory?: " + "No - it's a resource folder");
    
            try {
                BufferedImage image = ImageIO.read(Objects.requireNonNull(Main.class.getResource(imagePath)));
                System.out.println("Image read successful.");
            } catch (IOException e) {
                System.out.println("Image read failed.");
            }
            try (InputStream in = Objects.requireNonNull(Main.class.getResourceAsStream(audioPath))) {
                AudioInputStream audioInput = AudioSystem.getAudioInputStream(in);
                Clip clip = AudioSystem.getClip();
                clip.open(audioInput);
                clip.start();
                clip.loop(Clip.LOOP_CONTINUOUSLY);
                // Clip will start in its own thread so prevent the main thread from exiting right away
                Thread.sleep(4000);
            } catch (Exception e) {
                System.out.println("Read failed");
                throw new RuntimeException(e);
            }
        }
    }