最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用Java實現(xiàn)一個WAV文件信息解析與打印工具

 更新時間:2025年11月03日 09:59:48   作者:一鍵難忘  
在日常音頻處理工作中,我們經(jīng)常會遇到各種音頻文件格式,其中最經(jīng)典的無損音頻格式之一就是 WAV,所以本文將分享一個純 Java 實現(xiàn)的 WAV 文件信息解析工具,能夠從文件頭到數(shù)據(jù)塊完整打印 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 文件可能包含擴展塊,如 LISTfact,使用 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ù)。

五、擴展思路

支持更多格式
可以增加對 factLIST 等擴展塊的解析,也可支持非 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)文章

  • java多線程編程之使用Synchronized塊同步變量

    java多線程編程之使用Synchronized塊同步變量

    我們可以通過synchronized塊來同步特定的靜態(tài)或非靜態(tài)方法。要想實現(xiàn)這種需求必須為這些特性的方法定義一個類變量,然后將這些方法的代碼用synchronized塊括起來,并將這個類變量作為參數(shù)傳入synchronized塊
    2014-01-01
  • Java ResultSet案例講解

    Java ResultSet案例講解

    這篇文章主要介紹了Java ResultSet案例講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • SpringCloud Stream RabbitMQ動態(tài)路由Key問題

    SpringCloud Stream RabbitMQ動態(tài)路由Key問題

    文章主要描述了使用消息中間件實現(xiàn)不同操作后發(fā)送不同郵件的功能,通過設(shè)置路由key和group,使得生產(chǎn)者能夠根據(jù)郵件類型發(fā)送消息至對應(yīng)隊列,消費者則通過路由key篩選消息
    2026-05-05
  • 淺談Java中幾種常見的比較器的實現(xiàn)方法

    淺談Java中幾種常見的比較器的實現(xiàn)方法

    下面小編就為大家?guī)硪黄獪\談Java中幾種常見的比較器的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 將bean注入到Spring中的方式總結(jié)

    將bean注入到Spring中的方式總結(jié)

    在Java的Spring框架中,將bean注入到容器中是核心概念之一,這是實現(xiàn)依賴注入的基礎(chǔ),Spring提供了多種方式來將bean注入到容器中,本文給大家總結(jié)了將bean注入到Spring中的幾種方式,需要的朋友可以參考下
    2023-12-12
  • RabbitMQ,RocketMQ,Kafka?事務(wù)性,消息丟失,消息順序性和消息重復(fù)發(fā)送的處理策略問題

    RabbitMQ,RocketMQ,Kafka?事務(wù)性,消息丟失,消息順序性和消息重復(fù)發(fā)送的處理策略問題

    這篇文章主要介紹了RabbitMQ,RocketMQ,Kafka?事務(wù)性,消息丟失,消息順序性和消息重復(fù)發(fā)送的處理策略,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • java圖片和文本同時提交到表單的實例代碼

    java圖片和文本同時提交到表單的實例代碼

    在本篇文章里小編給大家整理的是關(guān)于java實現(xiàn)圖片和文本同時提交到表單的相關(guān)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2020-02-02
  • 輕松掌握Java備忘錄模式

    輕松掌握Java備忘錄模式

    這篇文章主要幫助大家輕松掌握Java備忘錄模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • Spring事務(wù)管理中關(guān)于數(shù)據(jù)庫連接池詳解

    Spring事務(wù)管理中關(guān)于數(shù)據(jù)庫連接池詳解

    事務(wù)的作用就是為了保證用戶的每一個操作都是可靠的,事務(wù)中的每一步操作都必須成功執(zhí)行,只要有發(fā)生異常就 回退到事務(wù)開始未進行操作的狀態(tài)。事務(wù)管理是Spring框架中最為常用的功能之一,我們在使用Spring Boot開發(fā)應(yīng)用時,大部分情況下也都需要使用事務(wù)
    2022-12-12
  • Java把list分成多個list的方法示例

    Java把list分成多個list的方法示例

    在編程中將大的list集合拆分為多個小集合可以提高處理效率,主要拆分方法包括等量拆分適用于均勻處理數(shù)據(jù)、?指定數(shù)量拆分按固定子集大小劃分、根據(jù)條件拆分按特定規(guī)則進行,這些方法有助于多線程異步處理,需要的朋友可以參考下
    2024-11-11

最新評論

盘山县| 乌海市| 图木舒克市| 张家港市| 乌拉特中旗| 新兴县| 诏安县| 涿州市| 富锦市| 彭泽县| 马尔康县| 塘沽区| 宜兴市| 东阳市| 丰县| 文昌市| 绥阳县| 奇台县| 宣城市| 明水县| 北宁市| 连南| 琼结县| 苍溪县| 淮南市| 棋牌| 田东县| 武宁县| 博湖县| 蒙阴县| SHOW| 青田县| 德保县| 曲沃县| 郑州市| 甘孜| 克东县| 汝阳县| 南漳县| 得荣县| 普定县|