当我尝试让 InputStream 与 jar Java Sound API 中的文件连接时出现 IO 异常
Posted
技术标签:
【中文标题】当我尝试让 InputStream 与 jar Java Sound API 中的文件连接时出现 IO 异常【英文标题】:An IOexception when I try to get an InputStream connected with a file inside a jar Java Sound API 【发布时间】:2021-12-16 15:35:05 【问题描述】:我正在编写一个使用 Java Sound 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 Sound API,尤其是我用来获取AudioInputStream
实例的AudioSystem
类,尝试在底层InputStream
上使用标记或重置操作。似乎这些输入流上不允许进行这些操作。
我完全糊涂了。我很奇怪javax.sound.sampled.AudioSystem
读取InputStream
的方式与javax.imageio.ImageIO
完全不同(使用ImageIO
我可以毫无问题地从罐子中读取图像)。
我该如何解决?显然,我可能会读取常规文件,而不是从 jar 中读取,但如果可能的话,我想完全从 jar 中读取声音。
我尝试使用 Java 8.0.302-open 和 Java 16.0.2-open 运行此代码。此外,如果这个问题是特定于平台的,我使用带有 Linux 内核版本 5.11.0-41-generic 的桌面 Ubuntu 20.04,不幸的是,我没有机会在其他平台上测试此代码。
已解决感谢@filpa,解决方案是将ClassLoader.getResourceAsStream()
获得的InputStream
包装到BufferedInputStream
或任何其他支持mark/reset
操作的输入流中。
【问题讨论】:
可能与this 问题及其答案有关。您是否尝试过将Audio.class.getClassLoader().getResourceAsStream(path)
包装在new BufferedInputStream()
中(或其他支持mark/reset
的InputStream
实现?
@filpa 非常感谢!事实证明,解决方案非常简单 XD 我显然应该为自己重新发现 java.io...
【参考方案1】:
引入声音资源的更简单方法是使用getResource()
而不是getResourceAsStream()
。在这种情况下无需换行。如果您向getAudioInputStream()
方法提供URL
而不是InputStream
,则可以避免与标记/重置功能相关的问题/错误。
在 *** 的 info area for the javasound tag 上发布了一些示例。基本上:
URL url = YourClass.class.getResource("youraudio.wav");
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
以上假设音频资源与 YourClass 类位于同一文件夹中。
附:如果您更喜欢答案(使用getResourceAsStream()
并换行,请实际将其写为答案并选择它。否则此问题会引诱喜欢帮助他人的人,认为此问题尚未得到回答。或者,邀请@filpa 发布他的信息作为答案并选择它。
【讨论】:
我总是推荐使用getResource()
,除了JavaSound 知道如何处理(包装的)流之外,还有Clip
被缓存的可能性。如果它以 URL 开头,则不需要重新加载。
感谢@Phil Freihofner 和 AndrewThompson!我明白你想说什么。我应该选择哪种解决方案值得考虑。在我的特殊情况下,我正在编写一个非常简单的基于 Java Swing 的游戏引擎,通常用于内部教育目的。当我为一年级学生准备这些材料时,我想表现并不重要。不过,再次感谢您的帮助,我会为自己的发展考虑选择。我会将这个答案标记为不打扰 filpa 的解决方案。
游戏循环是学生项目的好主意! FWIW,在使用 JavaFX 和 LibGDX/LWJGL 之前的几年中,jvm-gaming.org 上可能有一些成员编写的文章和代码,可以参考他们的想法(在他们的“文章和教程”部分)。祝您教学顺利!如果@filpa 主动提供他的答案作为答案,请随时切换您的答案名称。要点:感谢您更新此问题的状态。
FWIW 我完全同意这一点,再加上@AndrewThompson 的评论,这是公认的答案,因为它比我的评论(在技术上不适合代替重复投票)提供了更多的洞察力。
“否则这个问题会吸引那些喜欢帮助别人的人,认为这个问题还没有得到回答。” 呵呵..我建议将答案标记为已接受以后寻找答案的人受益。就我而言,我可能会得到一个包含 20 个问题的列表 - 但只会查看带有绿色勾号的列表!以上是关于当我尝试让 InputStream 与 jar Java Sound API 中的文件连接时出现 IO 异常的主要内容,如果未能解决你的问题,请参考以下文章
当 jar 文件从 URL 作为 InputStream 打开时,JarEntry.getSize() 返回 -1
来自 jar-File 的 InputStream 始终返回 null