当我尝试将 InputStream 与 jar 中的文件连接时出现 IOexception Java Sound API

An IOexception when I try to get an InputStream connected with a file inside a jar Java Sound API

我正在编写一个使用 Java 声音 API 播放声音的简单方法。我的想法是只播放 jar 中包含的 .wav 文件。对于图像,我可以使用 ClassLoader.getResourceAsStream() 轻松获得 InputStream 并从此流加载图像。但是,当我对声音使用相同的方法时,我得到 IOException.

Caused by: java.io.IOException: mark/reset not supported
    at java.base/java.util.zip.InflaterInputStream.reset(InflaterInputStream.java:290)
    at java.base/java.io.FilterInputStream.reset(FilterInputStream.java:224)
    at java.desktop/com.sun.media.sound.SunFileReader.getAudioFileFormat(SunFileReader.java:59)
    at java.desktop/com.sun.media.sound.WaveExtensibleFileReader.getAudioInputStream(WaveExtensibleFileReader.java:259)
    at java.desktop/javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1010)
    at ru.mrkefir.stepan.engine.sound.Audio.playImpl(Audio.java:34)

原因是AudioSystem.getAudioInputStream(),我使用了以下代码:

AudioInputStream stream = AudioSystem.getAudioInputStream(
     Audio.class.getClassLoader().getResourceAsStream(path)
);
Clip clip = AudioSystem.getClip();
clip.open(stream);
clip.setFramePosition(0);
clip.start();

我检查结果 InputStream 是否可以读取,显然它不为空。正如我从异常描述中了解到的那样,Java 声音 API 尤其是 AudioSystem class,我用它来获取 AudioInputStream 的实例,尝试在底层 InputStream 上使用标记或重置操作。似乎在此类输入流上不允许进行这些操作。

我完全糊涂了。 javax.sound.sampled.AudioSystem 以与 javax.imageio.ImageIO 完全不同的方式读取 InputStream 对我来说很奇怪(使用 ImageIO 我可以毫无问题地从罐子中读取图像)。

我该如何解决?显然我可能会读取一个常规文件,而不是从 jar 中读取,但如果可能的话,我想从 jars 中读取声音。

我尝试 运行 此代码 Java 8.0.302-open 和 Java 16.0.2-open。此外,如果这个问题是特定于平台的,我使用 Desktop Ubuntu 20.04 和 Linux Kernel version 5.11.0-41-generic,不幸的是,我没有机会在其他平台上测试这个代码平台。

已解决感谢@filpa,解决方案是将ClassLoader.getResourceAsStream()获得的InputStream包装到BufferedInputStream或任何其他输入流中支持 mark/reset 操作。

引入声音资源的更简单方法是使用 getResource() 而不是 getResourceAsStream()。在这种情况下不需要换行。如果您向 getAudioInputStream() 方法提供 URL 而不是 InputStream,则避免与 mark/reset 功能相关的 issues/errors。

在 Whosebug 的 info area for the javasound tag 上有 post 的示例。基本上:

URL url = YourClass.class.getResource("youraudio.wav");
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);

以上假定音频资源与 class YourClass 在同一文件夹中。

P.S。如果你更喜欢答案(使用getResourceAsStream()和换行,请实际写这个作为答案,并且select它。否则这个问题会吸引那些喜欢帮助别人的人,认为这个问题还没有已回答。或者,邀请@filpa post 他的信息作为答案并 select 它。