文章目录
- 一、前言
- 二、开始狼人杀
- 嫌疑人1:
- 嫌疑人2:
- 三、复盘
- Jdk8原生bug
- 解决方法和原理解析
一、前言
做了一个基于文字转语言的小接口,想删除本地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)
完