英文:
Java Sound API locks audio file after playing it
问题
我正在尝试使用Javax.sound播放一个.wav文件。
一切运行正常,文件按预期播放,最后我关闭了Clip和AudioInputStream。然而,在此之后,文件仍然被锁定(在使用中),我无法在不获得异常的情况下触摸它:java.nio.file.FileSystemException: alerting.wav: 进程无法访问该文件,因为它正在被另一个进程使用。
下面是代码示例:
static private class SoundThread extends Thread implements LineListener {
private boolean playCompleted;
private int cycles;
public SoundThread(int repeats) {
cycles = repeats;
}
@Override
public void run() {
Clip clip;
AudioInputStream inputStream;
File soundFile = new File("alerting.wav");
try {
inputStream = AudioSystem.getAudioInputStream(soundFile);
try {
clip = AudioSystem.getClip();
clip.addLineListener(this);
clip.open(inputStream);
while(cycles > 0) {
playCompleted = false;
clip.setFramePosition(0);
clip.start();
while(!playCompleted) {
Thread.sleep(1000);
}
Thread.sleep(audioRepeatTime * 1000);
cycles--;
}
//clip.drain();
clip.close();
inputStream.close();
System.out.println("All closed");
try {
this.finalize();
} catch (Throwable ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (Exception ex) {
Main.syslog(Level.WARNING, "E1001 无法播放警报声音", ex);
} finally {
inputStream.close();
}
} catch (UnsupportedAudioFileException ex) {
Main.syslog(Level.WARNING, "E1001 无法播放警报声音", ex);
} catch (IOException ex) {
Main.syslog(Level.WARNING, "E1001 无法播放警报声音", ex);
}
}
@Override
public void update(LineEvent event) {
LineEvent.Type type = event.getType();
System.out.println("Event: " + type);
if(type == LineEvent.Type.STOP) {
playCompleted = true;
} else if (type == LineEvent.Type.CLOSE) {
System.out.println("listener closed");
}
}
}
public static void PlayAlertSound() {
if(enableAudio) {
SoundThread st = new SoundThread(audioLoops);
st.start();
}
}
public static void PlayAlertSound(int repeats) {
if(enableAudio) {
SoundThread st = new SoundThread(repeats);
st.start();
}
}
在Java线程列表中,我看到“Java Sound Event Dispatcher”正在运行。我认为这是导致文件被锁定的原因。
您有什么办法可以解决这个问题吗?谢谢
<details>
<summary>英文:</summary>
I am trying to use Javax.sound to play a .wav file.
Everything works fine, the file plays as expected and in the end I close the Clip and I close the AudioInputStream. However, the file remains locked (in use) after that and I cannot touch it without getting an exception: java.nio.file.FileSystemException: alerting.wav: The process cannot access the file because it is being used by another process.
A sample of code is below:
static private class SoundThread extends Thread implements LineListener {
private boolean playCompleted;
private int cycles;
public SoundThread(int repeats) {
cycles = repeats;
}
@Override
public void run() {
Clip clip;
AudioInputStream inputStream;
File soundFile = new File("alerting.wav");
try {
inputStream = AudioSystem.getAudioInputStream(soundFile);
try {
clip = AudioSystem.getClip();
clip.addLineListener(this);
clip.open(inputStream);
while(cycles > 0) {
playCompleted = false;
clip.setFramePosition(0);
clip.start();
while(!playCompleted) {
Thread.sleep(1000);
}
Thread.sleep(audioRepeatTime * 1000);
cycles--;
}
//clip.drain();
clip.close();
inputStream.close();
System.out.println("All closed");
try {
this.finalize();
} catch (Throwable ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (Exception ex) {
Main.syslog(Level.WARNING, "E1001 could not play alert sound", ex);
} finally {
inputStream.close();
}
} catch (UnsupportedAudioFileException ex) {
Main.syslog(Level.WARNING, "E1001 could not play alert sound", ex);
} catch (IOException ex) {
Main.syslog(Level.WARNING, "E1001 could not play alert sound", ex);
}
}
@Override
public void update(LineEvent event) {
LineEvent.Type type = event.getType();
System.out.println("Event: " + type);
if(type == LineEvent.Type.STOP) {
playCompleted = true;
} else if (type == LineEvent.Type.CLOSE) {
System.out.println("listener closed");
}
}
}
public static void PlayAlertSound() {
if(enableAudio) {
SoundThread st = new SoundThread(audioLoops);
st.start();
}
}
public static void PlayAlertSound(int repeats) {
if(enableAudio) {
SoundThread st = new SoundThread(repeats);
st.start();
}
}
In the Java threads list I see "Java Sound Event Dispatcher" running. I think this is what keeps the file locked.
Any idea how can I fix this? Thanks
</details>
# 答案1
**得分**: 1
The API for Clip states:
> 注意,一些一旦关闭的线路将无法重新打开。尝试重新打开这种线路将始终导致 `LineUnavailableException`。
我将提出几点额外的建议。
与其使用 `File`,更好的加载音频资源的方法是使用 `class.getResource` 方法。这个方法会返回一个 `URL`,你可以将其作为参数传递给 `AudioSystem.getAudioInputStream` 方法。
我不清楚你试图做什么,但我还建议对你的代码进行进一步的更改。在同一个方法中初始化和播放 `Clip` 通常是不推荐的,因为这违反了 `Clip` 的预期用途。`Clip` 适用于可以保存在内存中的声音。所以,将你的 `Clip` 声明为实例变量。然后,将加载和打开 `Clip` 的代码放在它自己的方法中。并且将调用 `start` 或 `loop` 的代码放在单独的方法中,除非你确定不会再次播放它,否则不要在播放结束时关闭 `Clip`。
如果使用 `clip.loop`,你就不必担心监听器和迭代次数。
<details>
<summary>英文:</summary>
The API for Clip states:
> Note that some lines, once closed, cannot be reopened. Attempts to
> reopen such a line will always result in a `LineUnavailableException`.
I'm going to make a couple additional suggestions.
Instead of using `File`, a better way to load audio resources is with the `class.getResource` method. This method returns a `URL` which you can then pass as your argument to the `AudioSystem.getAudioInputStream` method.
I'm not clear what you are trying to do, but I also recommend some further changes to your code. Initializing and playing a `Clip` in the same method is not generally done, as it goes against the intended use of the `Clip`. A `Clip` is meant for sounds that can be held in memory. So, make your `Clip` an instance variable. Then, place the code that loads and opens the `Clip` in its own method. And put the code that calls `start` or `loop` in a separate method or methods, and don't close the `Clip` at the end of playing unless you are sure you are not going to ever play it again.
If you use `clip.loop`, you don't have to bother with listeners and count iterations.
</details>
# 答案2
**得分**: 0
替代方式:
```java
//...
AudioInputStream inputStream;
File soundFile = new File("alerting.wav");
try {
byte[] bytes = Files.readAllBytes(soundFile.toPath());
inputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes));
// ...
}
// ...
英文:
Instead of:
//...
AudioInputStream inputStream;
File soundFile = new File("alerting.wav");
try {
inputStream = AudioSystem.getAudioInputStream(soundFile);
// ...
}
// ...
Try this:
//...
AudioInputStream inputStream;
File soundFile = new File("alerting.wav");
try {
byte[] bytes = Files.readAllBytes(soundFile.toPath());
inputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes));
// ...
}
// ...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论