无法将InputStream对象传递给Java Sound API

sof*_*sof 4 java javasound

它可以与File传递给的对象一起使用AudioSystem#getAudioFileFormat,但是为什么InputStream下面的对象不能通过呢?有什么建议吗?

import java.io.*;
import javax.sound.sampled.*;

public class Test {

    public static void main(String[] args) throws Exception {

        AudioSystem.getAudioFileFormat(new File(
                "myaudio.wav"));
        AudioSystem.getAudioFileFormat(new FileInputStream(
                "myaudio.wav"));

    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Exception in thread "main" java.io.IOException: mark/reset not supported
    at java.io.InputStream.reset(InputStream.java:330)
    at com.sun.media.sound.WaveFileReader.getAudioFileFormat(WaveFileReader.java:88)
    at javax.sound.sampled.AudioSystem.getAudioFileFormat(AudioSystem.java:985)
    at Test.main(Test.java:10)
Run Code Online (Sandbox Code Playgroud)

@编辑

据答案@René Jeschke@Phil Freihofner并且@Andrew Thompson,无论mark/reset被要求作为强制性protocal为Java Sound API与互动IO stream,恕我直言,类型buffered流,而不是raw一个应该被专门定义为参数的签名传递。这样做将使收窄到更理想的结果,而不是任意接受IO stream然后诉诸IOException为不利指标。

Nee*_*eet 5

FileInputStream不支持标记/重置(用于随机访问),请将其包装为BufferedInputStream以获得标记/重置支持。

编辑:为什么会这样?getAudioFileFormat遍历当前注册的每个音频文件阅读器。每个阅读器都尝试通过读取某些特定字节来识别文件格式。因此,每个阅读器都必须撤消对流的更改(以允许其他阅读器在需​​要时重新读取所有数据)。

当您提供时File,这不是问题,因为每个阅读器只是打开一个新流,但是当您传递一个流时,每个阅读器必须标记当前流的位置,进行读取,并在完成后将流重置为其开始状态。

这就是为什么需要BufferedInputStream它的原因,因为它添加了一个内存中的缓冲区来支持标记/重置。

Edit2:因为问题是“为什么FileInputStream失败?” 我没有提出任何解决方法或替代方法,但试图解释为什么使用时失败FileInputStream。在某些情况下,您将无法使用URL或类似内容(例如,考虑到包含音频文件的二进制打包文件)。