Java IO异常:从AudioInputStream写入文件时流关闭

时间:2014-10-23 01:27:02

标签: java audio stream ioexception

所以我的下面的代码片段( concat 方法)主要尝试做两件事:

  1. 将多个AudioInputStream(从源文件列表中读取)连接成一个最终的长流
  2. 将该流写入目标WAV文件

    public static void concat(ArrayList<String> sourceFiles, String targetFile) {
        AudioInputStream targetBuilder = null;
        String file;
        AudioInputStream nextSource;
        for (int i = 0; i < sourceFiles.size(); i++)
        {
            file = sourceFiles.get(i);
            if(targetBuilder == null)
            {
                targetBuilder = AudioSystem.getAudioInputStream(new File(file));
                continue;
            }
            nextSource = AudioSystem.getAudioInputStream(new File(file));
            AudioInputStream appendedFiles = new AudioInputStream(
                    new SequenceInputStream(targetBuilder, nextSource),     
                    targetBuilder.getFormat(), 
                    targetBuilder.getFrameLength() + nextSource.getFrameLength());
            targetBuilder = appendedFiles;
            nextSource.close();
        }
        AudioSystem.write(targetBuilder, AudioFileFormat.Type.WAVE, new File(targetFile));
        targetBuilder.close();
    }
    
  3. 这个想法借鉴了这个主题:Join two WAV files from Java。现在的问题是连续几次执行这个片段之后,最终会在AudioSystem.write()行上的“stream closed”上抛出IO Exception。堆栈跟踪如下所示:

    java.io.IOException: Stream Closed
    at java.io.FileInputStream.readBytes(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:272)
    at javax.sound.sampled.AudioInputStream.read(AudioInputStream.java:292)
    at java.io.SequenceInputStream.read(SequenceInputStream.java:208)
    at java.io.SequenceInputStream.read(SequenceInputStream.java:211)
    at javax.sound.sampled.AudioInputStream.read(AudioInputStream.java:292)
    at java.io.SequenceInputStream.read(SequenceInputStream.java:208)
    at javax.sound.sampled.AudioInputStream.read(AudioInputStream.java:292)
    ......//with the exact same two lines repeating lots of times
    at java.io.SequenceInputStream.read(SequenceInputStream.java:208)
    at javax.sound.sampled.AudioInputStream.read(AudioInputStream.java:292)
    at com.sun.media.sound.SunFileWriter$NoCloseInputStream.read(SunFileWriter.java:198)
    at java.io.SequenceInputStream.read(SequenceInputStream.java:208)
    at java.io.InputStream.read(InputStream.java:101)
    at com.sun.media.sound.WaveFileWriter.writeWaveFile(WaveFileWriter.java:239)
    at com.sun.media.sound.WaveFileWriter.write(WaveFileWriter.java:137)
    at javax.sound.sampled.AudioSystem.write(AudioSystem.java:1354)
    at com.mycompany.mypackage.AudioUtils.concat(AudioUtils.java:324)
    ......
    

    所以在我看来,当程序仍然试图从AudioInputStream中读取更多字节到文件时,但在某些时候,流( targetBuilder )只是自行关闭。这对我没有意义,因为我只在我的AudioSystem.write()方法之后关闭了这个流。

    现在,如果我真的在for循环中注释这一行:

    //nextSource.close();
    

    这个流关闭异常似乎消失了,替换了“FilesNotFoundException:太多的打开文件”,这对我来说很有意义,因为在循环的每次迭代中我都在创建一个新的AudioInputStream并分配对nextSource的引用,但是如果我从不关闭它,最终我用完了打开的文件描述符。

    然而我不明白的是,如何关闭此 nextSource 流会以何种方式影响 targetBuilder 流的行为?如果我关闭 nextSource 流,为什么这个流会突然关闭? (我假设两者之间存在联系,如果我错了,请纠正我。)

    谢谢!

1 个答案:

答案 0 :(得分:0)

SequenceInputStream不会在内存中复制你的流,它只记得链接......这里是读取方法的代码

public int read() throws IOException
{
  int ch = -1;

  while (in != null && (ch = in.read()) < 0)
    {
      in.close();
      in = getNextStream();
    }

  return ch;
}

因此,如果您将关闭添加到SequenceInputStream的其中一个流 - 您将获得异常