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

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

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

二、Java實現(xiàn)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",確保文件是標(biāo)準 WAV 文件。
讀取 fmt 塊
fmt 塊是 WAV 文件的核心,存儲 PCM 或壓縮格式信息:
- AudioFormat:1 表示 PCM,其他值表示壓縮音頻
- NumChannels:聲道數(shù)(1 = 單聲道,2 = 雙聲道)
- SampleRate:采樣率(如 44100 Hz)
- ByteRate:每秒字節(jié)數(shù) = SampleRate × NumChannels × BitsPerSample/8
- BlockAlign:每個采樣塊字節(jié)數(shù) = NumChannels × BitsPerSample/8
- BitsPerSample:每個樣本的位深度
讀取 data 塊
data 塊存儲實際音頻數(shù)據(jù),長度就是 Subchunk2Size,可用于計算音頻時長:
if (byteRate > 0)
System.out.printf("音頻時長 : %.2f 秒%n", dataSize * 1.0 / byteRate);
通過 dataSize / byteRate 可以得到音頻時長(秒)。
跳過其他擴展塊
WAV 文件可能包含擴展塊,如 LIST 或 fact,使用 fis.skip(subchunkSize) 跳過即可,不影響 PCM 解析。
四、運行效果示例
假設(shè)有一個單聲道 16bit、采樣率 44100Hz 的 WAV 文件 11.wav,打印結(jié)果類似:
====== 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 秒 ===========================
通過這個輸出,我們可以快速獲得音頻的各項參數(shù),并為后續(xù)處理(如剪輯、拼接、變速)提供依據(jù)。


五、擴展思路
支持更多格式
可以增加對 fact、LIST 等擴展塊的解析,也可支持非 PCM 壓縮 WAV 文件。
批量解析
將 printWavInfo 封裝成工具類,可遍歷目錄下所有 WAV 文件,批量打印信息或?qū)С龅?CSV。
音頻處理集成
通過 Java 內(nèi)存流操作(ByteArrayOutputStream + AudioInputStream)可實現(xiàn)高性能純本地音頻處理,無需 FFmpeg。
- 拼接多個 WAV 文件
- 剪切指定時間段
- 改變采樣率或位深度
音頻可視化
結(jié)合 Java 圖形庫(如 Swing、JavaFX)繪制波形圖,實現(xiàn)音頻可視化分析。
六、總結(jié)
本文介紹了一個 純 Java 實現(xiàn)的 WAV 文件信息打印工具,從文件頭解析到 fmt 塊和 data 塊,能夠打?。?/p>
- 音頻格式(PCM 或壓縮)
- 聲道數(shù)
- 采樣率
- 每秒字節(jié)數(shù)
- 每個采樣塊字節(jié)數(shù)
- 位深度
- 音頻時長
相比依賴 FFmpeg 等外部工具,這種純 Java 方法更輕量、可嵌入 Java 項目,并能在內(nèi)存中快速處理 WAV 文件。
掌握 WAV 文件結(jié)構(gòu)和 Java 文件流操作之后,你就可以在此基礎(chǔ)上擴展音頻處理功能,例如音頻拼接、分割、變速甚至實時處理。
到此這篇關(guān)于利用Java實現(xiàn)一個WAV文件信息解析與打印工具的文章就介紹到這了,更多相關(guān)Java WAV信息解析與打印內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloud Stream RabbitMQ動態(tài)路由Key問題
文章主要描述了使用消息中間件實現(xiàn)不同操作后發(fā)送不同郵件的功能,通過設(shè)置路由key和group,使得生產(chǎn)者能夠根據(jù)郵件類型發(fā)送消息至對應(yīng)隊列,消費者則通過路由key篩選消息2026-05-05
RabbitMQ,RocketMQ,Kafka?事務(wù)性,消息丟失,消息順序性和消息重復(fù)發(fā)送的處理策略問題
這篇文章主要介紹了RabbitMQ,RocketMQ,Kafka?事務(wù)性,消息丟失,消息順序性和消息重復(fù)發(fā)送的處理策略,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-03-03
Spring事務(wù)管理中關(guān)于數(shù)據(jù)庫連接池詳解
事務(wù)的作用就是為了保證用戶的每一個操作都是可靠的,事務(wù)中的每一步操作都必須成功執(zhí)行,只要有發(fā)生異常就 回退到事務(wù)開始未進行操作的狀態(tài)。事務(wù)管理是Spring框架中最為常用的功能之一,我們在使用Spring Boot開發(fā)應(yīng)用時,大部分情況下也都需要使用事務(wù)2022-12-12

