Jar не будет воспроизводить звуки из папки ресурсов, загруженной через getClass () - PullRequest
0 голосов
/ 04 августа 2020

У меня такая структура каталогов:

root
  resources
    .png files
    Music.mid
    Sound.wav
  src
    .java files

, и я проигрываю звуки из папки ресурсов, используя этот код

    public void play()  {
        try  {
            URL defaultSound = getClass().getResource(filename);
            AudioInputStream audioInputStream = 
                    AudioSystem.getAudioInputStream(defaultSound);
            Clip clip = AudioSystem.getClip();
            clip.open(audioInputStream);
            clip.start( );
            while (clip.isRunning()) {}

        }
        catch (Exception e)  {
            e.printStackTrace();
        }
    }

Я передаю ему имена файлов = /resources/Music.mid и /resources/Sound.wav.

Он отлично работает, когда я запускаю его в IDE, но когда я упаковываю его в jar (все файлы musi c находятся внутри jar, я проверил), он не воспроизводит звук и выдает исключение :

FileNotFoundException: syntax error in file name, directory name or disk name.

Почему это происходит и как это исправить?

1 Ответ

0 голосов
/ 04 августа 2020

getClass () возвращает URL-адрес, а не объект File. Это происходит потому, что загрузчики классов (которые использует .getResource) - абстрактное понятие, а «ресурс» может быть чем угодно. Это не обязательно должен быть файл. Это может быть запись в файле jar (который на самом деле является zip). Это может быть запись в файле jmod (который представляет собой настраиваемый формат контейнера, представленный в JDK9). Это может быть большой двоичный объект в столбце базы данных. Файл на сервере webdav. Или даже генерируется «на лету» каждый раз, когда вы запрашиваете ресурс. Все идет.

Очевидно, ваша библиотека аудиоплеера устарела или хреновая. Он ДЕЛАЕТ позволяет вам передать ему URL-адрес, но библиотека аудиоплеера, которую вы используете, просто извлечет sh, если этот URL-адрес не является чем-либо, кроме того, который представляет собой фактический файл на диске.

При работе в среде IDE это ЕСТЬ файл на диске. При запуске как jar он является таким же допустимым ресурсом, как и все, что создает загрузчик классов, но из-за того, что эта библиотека проигрывателя не справляется с любым URL-адресом (кроме URL-адресов file: //), происходит сбой.

Есть только два решения:

  1. Получите лучшую библиотеку.
  2. Найдите временный каталог, распакуйте в него ресурс, затем передайте временный файл (или, возможно, URL-адрес, представляющий этот temp) в вашу библиотеку.

Вариант № 2 довольно сложен. Вам нужно найти место с доступом для записи, и после этого вам нужно будет удалить файл. Это также пустая трата дисковых циклов. Но при необходимости вы, конечно, можете сделать так:

public void play() throws Exception {
  File f = File.createTempFile("Sound.wav");
  f.deleteOnExit();
  try (InputStream in = YourPlayer.class.getResourceAsStream("/resources/Sound.wav");
  OutputStream out = new FileOutputStream(f)) {
     in.transferTo(out);
  }

  AudioInputStream audioInputStream = 
                    AudioSystem.getAudioInputStream(f.toURI().toURL());
            Clip clip = AudioSystem.getClip();
            clip.open(audioInputStream);
            clip.start( );
            while (clip.isRunning()) {}
}

NB: getClass().getResource() немного неверно; правильный синтаксис - ClassThisCodeIsIn.class.getResource. Обычно работают оба, но бывают случаи, когда последнее работает, а первое - нет (например, когда вы подклассифицируете). Это хорошая привычка никогда не писать код, который строго уступает чему-то столь же простому, даже если в данном конкретном случае это, вероятно, не имеет значения.

...