利用Java實現一個WAV文件信息解析與打印工具
引言
在日常音頻處理工作中,我們經常會遇到各種音頻文件格式,其中最經典的無損音頻格式之一就是 WAV(Waveform Audio File Format)。WAV 文件以 PCM(脈沖編碼調制)形式存儲音頻數據,結構相對簡單,但了解其內部細節(jié)對于音頻處理、剪輯、合并和分析都非常重要。

本文將分享一個純 Java 實現的 WAV 文件信息解析工具,能夠從文件頭到數據塊完整打印 WAV 文件信息,包括音頻時長、采樣率、通道數等關鍵信息。通過閱讀本文,你不僅可以掌握 WAV 文件結構,也可以基于此實現音頻分析、剪輯或轉換工具。

一、WAV 文件結構概述
WAV 文件采用 RIFF(Resource Interchange File Format) 容器格式,其結構大致如下:
+------------------+------------------+-----------------+ | ChunkID "RIFF" | ChunkSize | Format "WAVE" | +------------------+------------------+-----------------+ | Subchunk1ID "fmt "| Subchunk1Size | AudioFormat ... | +------------------------------------------------------+ | Subchunk2ID "data"| Subchunk2Size | 音頻數據 | +------------------------------------------------------+
- ChunkID(4字節(jié)):標識文件類型,一般為
"RIFF"。 - ChunkSize(4字節(jié)):整個文件大小減去 8 字節(jié)。
- Format(4字節(jié)):文件格式標識,一般為
"WAVE"。 - Subchunk1(fmt 塊):存儲音頻格式信息,如 PCM、采樣率、聲道數等。
- Subchunk2(data 塊):存儲實際音頻數據。
WAV 文件還可能包含其他擴展塊,如 LIST、fact 等,但對于 PCM 音頻,我們最關心的還是 fmt 和 data 塊。

二、Java實現WAV信息解析
下面是完整代碼示例,我們逐步解析:
public static void main(String[] args) throws Exception {
File wavFile1 = new File("D:/input/11.wav");
printWavInfo(wavFile1);
File wavFile2 = new File("D:/input/test2.wav");
printWavInfo(wavFile2);
File wavFile = new File("D:/input/1.wav");
printWavInfo(wavFile);
}
/**
* 打印WAV文件頭信息
*/
public static void printWavInfo(File wavFile) throws IOException {
try (FileInputStream fis = new FileInputStream(wavFile)) {
byte[] header = new byte[12];
if (fis.read(header) != 12) throw new IOException("WAV文件頭長度不足 12 字節(jié)");
String chunkID = new String(header, 0, 4);
int chunkSize = ByteBuffer.wrap(header, 4, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
String format = new String(header, 8, 4);
if (!"RIFF".equals(chunkID) || !"WAVE".equals(format)) {
throw new IOException("不是有效的WAV文件");
}
System.out.println("====== WAV 文件信息 ======");
System.out.println("文件路徑: " + wavFile.getAbsolutePath());
System.out.println("ChunkID : " + chunkID);
System.out.println("ChunkSize : " + chunkSize + " bytes");
System.out.println("Format : " + format);
String subchunkID;
int subchunkSize;
short audioFormat = 1, numChannels = 1, bitsPerSample = 16;
int sampleRate = 0, byteRate = 0, blockAlign = 0;
int dataSize = 0;
byte[] chunkHeader = new byte[8];
while (fis.read(chunkHeader) == 8) {
subchunkID = new String(chunkHeader, 0, 4);
subchunkSize = ByteBuffer.wrap(chunkHeader, 4, 4)
.order(ByteOrder.LITTLE_ENDIAN)
.getInt();
if ("fmt ".equals(subchunkID)) {
byte[] fmtData = new byte[subchunkSize];
fis.read(fmtData);
ByteBuffer bb = ByteBuffer.wrap(fmtData).order(ByteOrder.LITTLE_ENDIAN);
audioFormat = bb.getShort();
numChannels = bb.getShort();
sampleRate = bb.getInt();
byteRate = bb.getInt();
blockAlign = bb.getShort();
bitsPerSample = bb.getShort();
} else if ("data".equals(subchunkID)) {
dataSize = subchunkSize;
break; // 找到 data,停止讀取
} else {
// 跳過不需要的塊
fis.skip(subchunkSize);
}
}
System.out.println("AudioFormat : " + audioFormat + (audioFormat == 1 ? " (PCM)" : " (壓縮格式)"));
System.out.println("NumChannels : " + numChannels);
System.out.println("SampleRate : " + sampleRate + " Hz");
System.out.println("ByteRate : " + byteRate);
System.out.println("BlockAlign : " + blockAlign);
System.out.println("BitsPerSample : " + bitsPerSample);
System.out.println("Subchunk2ID : data");
System.out.println("Subchunk2Size : " + dataSize + " bytes");
if (byteRate > 0)
System.out.printf("音頻時長 : %.2f 秒%n", dataSize * 1.0 / byteRate);
System.out.println("===========================");
}
}
三、代碼解析
文件頭驗證
String chunkID = new String(header, 0, 4);
String format = new String(header, 8, 4);
if (!"RIFF".equals(chunkID) || !"WAVE".equals(format)) throw new IOException("不是有效的WAV文件");
這里讀取前 12 字節(jié)并驗證 "RIFF" 和 "WAVE",確保文件是標準 WAV 文件。
讀取 fmt 塊
fmt 塊是 WAV 文件的核心,存儲 PCM 或壓縮格式信息:
- AudioFormat:1 表示 PCM,其他值表示壓縮音頻
- NumChannels:聲道數(1 = 單聲道,2 = 雙聲道)
- SampleRate:采樣率(如 44100 Hz)
- ByteRate:每秒字節(jié)數 = SampleRate × NumChannels × BitsPerSample/8
- BlockAlign:每個采樣塊字節(jié)數 = NumChannels × BitsPerSample/8
- BitsPerSample:每個樣本的位深度
讀取 data 塊
data 塊存儲實際音頻數據,長度就是 Subchunk2Size,可用于計算音頻時長:
if (byteRate > 0)
System.out.printf("音頻時長 : %.2f 秒%n", dataSize * 1.0 / byteRate);
通過 dataSize / byteRate 可以得到音頻時長(秒)。
跳過其他擴展塊
WAV 文件可能包含擴展塊,如 LIST 或 fact,使用 fis.skip(subchunkSize) 跳過即可,不影響 PCM 解析。
四、運行效果示例
假設有一個單聲道 16bit、采樣率 44100Hz 的 WAV 文件 11.wav,打印結果類似:
====== WAV 文件信息 ====== 文件路徑: D:/input/11.wav ChunkID : RIFF ChunkSize : 42221196 bytes Format : WAVE AudioFormat : 1 (PCM) NumChannels : 1 SampleRate : 44100 Hz ByteRate : 88200 BlockAlign : 2 BitsPerSample : 16 Subchunk2ID : data Subchunk2Size : 42221184 bytes 音頻時長 : 478.57 秒 ===========================
通過這個輸出,我們可以快速獲得音頻的各項參數,并為后續(xù)處理(如剪輯、拼接、變速)提供依據。


五、擴展思路
支持更多格式
可以增加對 fact、LIST 等擴展塊的解析,也可支持非 PCM 壓縮 WAV 文件。
批量解析
將 printWavInfo 封裝成工具類,可遍歷目錄下所有 WAV 文件,批量打印信息或導出到 CSV。
音頻處理集成
通過 Java 內存流操作(ByteArrayOutputStream + AudioInputStream)可實現高性能純本地音頻處理,無需 FFmpeg。
- 拼接多個 WAV 文件
- 剪切指定時間段
- 改變采樣率或位深度
音頻可視化
結合 Java 圖形庫(如 Swing、JavaFX)繪制波形圖,實現音頻可視化分析。
六、總結
本文介紹了一個 純 Java 實現的 WAV 文件信息打印工具,從文件頭解析到 fmt 塊和 data 塊,能夠打?。?/p>
- 音頻格式(PCM 或壓縮)
- 聲道數
- 采樣率
- 每秒字節(jié)數
- 每個采樣塊字節(jié)數
- 位深度
- 音頻時長
相比依賴 FFmpeg 等外部工具,這種純 Java 方法更輕量、可嵌入 Java 項目,并能在內存中快速處理 WAV 文件。
掌握 WAV 文件結構和 Java 文件流操作之后,你就可以在此基礎上擴展音頻處理功能,例如音頻拼接、分割、變速甚至實時處理。
到此這篇關于利用Java實現一個WAV文件信息解析與打印工具的文章就介紹到這了,更多相關Java WAV信息解析與打印內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Mybatis之@ResultMap,@Results,@Result注解的使用
這篇文章主要介紹了Mybatis之@ResultMap,@Results,@Result注解的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

