【踩坑】JDK1.8 AudioSystem 无法关闭流的问题

发布时间:2024年01月10日

一、前言

做了一个基于文字转语言的小接口,想删除本地wav文件来着,结果发现删除不了。
很明显被占用了,还是被Java占用了…

在这里插入图片描述

二、开始狼人杀

嫌疑人1:

之前的代码是有一个spring的工具类FileCopyUtils.copy()使用


FileCopyUtils.copy(file, Paths.get(absPath).toFile());
if (file.exists() && !file.delete()){
	System.out.println(file.getAbsolutePath() + "删除失败");
}

看起来很正常,里面更正常:

public static int copy(InputStream in, OutputStream out) throws IOException {
	Assert.notNull(in, "No InputStream specified");
	Assert.notNull(out, "No OutputStream specified");

	int var2;
	try {
		var2 = StreamUtils.copy(in, out);
	} finally {
		close(in);
		close(out);
	}
	return var2;
}

close(in); close(out);很好很好,直接发个金水

嫌疑人2:

想到流程中用了Jdk8 javax.sound.sampled包下的 AudioInputStream,用于获取wav音频文件的时长,我是这样写的:

public static int getSoundLength(String filePath) {
	File file = new File(filePath);
	double duration;
	try(AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file)){
		int sampleRate = (int) audioInputStream.getFormat().getSampleRate();
		int dataSize = audioInputStream.available();
		duration = dataSize / (sampleRate*audioInputStream.getFormat().getFrameSize());
	} catch (UnsupportedAudioFileException | IOException e) {
		return 0;
	}
	return (int) duration;
}

我觉得我调用的也没问题,但是我把这个功能删掉之后文件就不占用了,这个直接标铁狼

三、复盘

Jdk8原生bug

博客园找到了类似的贴子:https://www.cnblogs.com/hligy/p/17659473.html
包括给Jdk官方提交的bug票:https://bugs.openjdk.org/browse/JDK-8013586

在这里插入图片描述
1.7u9报的,看情况应该是在17修复了这个bug,直接润,换成别的方法实现

解决方法和原理解析

用Java内置的java.io.DataInputStream来读wav头文件

  • 代码
	import java.io.DataInputStream;
	import java.io.File;
	import java.io.FileInputStream;
	
    public static int getSoundLength(String filePath) {
        File audioFile = new File(filePath);
        int duration = 0;
        try (FileInputStream fis = new FileInputStream(audioFile);
             DataInputStream dis = new DataInputStream(fis)) {
            // 读取 WAV 文件的头部信息
            byte[] header = new byte[44]; // WAVE 文件头部长度固定为 44 字节
            dis.readFully(header);
            // 解析头部信息获取时长
            int sampleRate = (header[24] & 0xff) | ((header[25] & 0xff) << 8);
            int bitsPerSample = (header[34] & 0xff) | ((header[35] & 0xff) << 8);
            int channels = (header[22] & 0xff) | ((header[23] & 0xff) << 8);
            duration = (int) ((audioFile.length() - 44) * 8 / (sampleRate * bitsPerSample * channels));
        } catch (IOException e) {
            System.err.println("处理音频文件时发生错误: " + e.getMessage());
        }
        return duration;
    }
  • postman返回音频时长12秒
    在这里插入图片描述

  • idea控制台结果12秒:
    在这里插入图片描述

很好用,很润,用到的方法是:

在处理wav文件时,需要根据大小得到准确的播放时长,这中间是有确定关系的
Size = ((Rate * 1000 * Precision * Channels * Length) / 8) + 44 

参数说明:
Size : 文件大小,Byte
Rate :采样率,kHz
Precision : 采样位数,bit
Channels : 声道数量
Length : 音频长度,s()

那么根据反过来根据文件大小计算播放长度公式就是:
Length = (Size - 44) * 8 / (Rate * 1000 * Precision * Channerls)

文章来源:https://blog.csdn.net/qq_40248814/article/details/135512926
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。