Java 实现MP3文件信息读取_mp3audioheader_遇见1995的博客-程序员宅基地

技术标签: mp3文件信息读取  Java  

前言:

最近在做实训,写一个音乐播放器,将文件存储在服务端,然后将相应的数据信息添加到数据库中。不想一个个手动添加,所以在百度之后发现MP3文件本身是只带这些信息的。

 

更新因为目前mp3文件中ID3v1的信息较少导致下述代码不能正常获取相关信息.

 

我对下述代码进行了改进. 具体项目代码地址

 

主要变动.

1. 使用由获取ID3v1中的信息变成了获取,ID3v2中的信息.

2. 去除了字符串过滤.

 

class MusicUtil {

    private static final String SONG_NAME_KEY = "TIT2";
    private static final String ARTIST_KEY = "TPE1";
    private static final String ALBUM_KEY = "TALB";

    /**
     * 通过歌曲文件地址, 获取歌曲信息
     *
     * @param filePath 歌曲文件地址
     * @return 歌曲信息
     * @throws Exception 可能抛出空指针异常
     */
    static Music getMusicInfo(String filePath) throws Exception {

        Music music = null;

        try {

            MP3File mp3File = (MP3File) AudioFileIO.read(new File(filePath));

            MP3AudioHeader audioHeader = (MP3AudioHeader) mp3File.getAudioHeader();

            // 歌曲名称
            String songName = getInfoFromFrameMap(mp3File, SONG_NAME_KEY);
            // 歌手名称
            String artist = getInfoFromFrameMap(mp3File, ARTIST_KEY);
            // 歌曲专辑
            String album = getInfoFromFrameMap(mp3File, ALBUM_KEY);
            // 播放时长
            int duration = audioHeader.getTrackLength();

            // 封装到music对象
            music = new Music(songName, artist, album, duration, filePath);

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件读取失败!" + e);
        }

        return music;
    }

    /**
     * 通过键值,获取歌曲中对应的字段信息
     *
     * @param mp3File mp3音乐文件
     * @param key     键值
     * @return 歌曲信息
     * @throws Exception 可能抛出空指针异常
     */
    private static String getInfoFromFrameMap(MP3File mp3File, String key) throws Exception {
        ID3v23Frame frame = (ID3v23Frame) mp3File.getID3v2Tag().frameMap.get(key);
        return frame.getContent();
    }
}

 

1、简述原理

MP3文件本身是自带音乐相关的信息比如,歌名,歌手,专辑等。

我们需要的信息在ID3v1或ID3v2的标签位置。

这里我们需要用到的jaudiotagger-2.2.6-SNAPSHOT.jar这个包

下载地址(还包含相关的音乐jar包)

2、主要代码

这里将读取的信息存放到music对象中去,然后返回这个对象。

private Music getSongInfo(String filePath) {
        
        Music music = null;

        try {

            MP3File mp3File = (MP3File) AudioFileIO.read(new File(filePath));
            MP3AudioHeader audioHeader = (MP3AudioHeader) mp3File.getAudioHeader();
            ID3v1Tag tag = mp3File.getID3v1Tag();//获取ID3v1的信息

            String songname = String.valueOf(tag.getTitle());//歌名
            String artist = String.valueOf(tag.getArtist());//歌手
            String album = String.valueOf(tag.getAlbum());//专辑
            int duration = audioHeader.getTrackLength();//时长

            //封装到music对象
            music = new Music(songname, artist, album, duration, filePath);
            

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件读取失败!"+e);
        }

        return music;
}

3、测试实例

music类:

package model;

public class Music {
    
    private int id;//音乐编号
    private String name;//音乐名
    private String singer;//歌手名
    private String album;//专辑名
    private int duration;//时长,以秒为单位
    private String path;//音乐文件存放路径

    /*
       无参构造器
     */
    public Music(){
        
    }

    public Music(String name, String singer, String album, int duration, String path) {
        this.name = name;
        this.singer = singer;
        this.album = album;
        this.duration = duration;
        this.path = path;
    }

    public Music(int id, String name, String singer, String album, int duration, 
        String path) {

        this.id = id;
        this.name = name;
        this.singer = singer;
        this.album = album;
        this.duration = duration;
        this.path = path;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSinger() {
        return singer;
    }

    public void setSinger(String singer) {
        this.singer = singer;
    }

    public int getDuration() {
        return duration;
    }

    public void setDuration(int duration) {
        this.duration = duration;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getAlbum() {
        return album;
    }

    public void setAlbum(String album) {
        this.album = album;
    }

    @Override
    public String toString() {
        return "Music{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", singer='" + singer + '\'' +
                ", duration=" + duration +
                ", path='" + path + '\'' +
                '}';
    }
}

测试代码:

package test;

import model.Music;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.mp3.MP3AudioHeader;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.id3.ID3v1Tag;

import java.io.File;

public class TestMP3 {

    public static void main(String[] args) {
        Music music = new TestMP3().getSongInfo(
            "D:\\CloudMusic\\Alexandra Streliski - Le départ.mp3");
        
        System.out.println(music.toString());
    }

    private Music getSongInfo(String filePath) {
        Music music = null;

        try {

            MP3File mp3File = (MP3File) AudioFileIO.read(new File(filePath));
            MP3AudioHeader audioHeader = (MP3AudioHeader) mp3File.getAudioHeader();
            ID3v1Tag tag = mp3File.getID3v1Tag();

            String songname = String.valueOf(tag.getTitle());//歌名
            String artist = String.valueOf(tag.getArtist());//歌手
            String album = String.valueOf(tag.getAlbum());//专辑
            int duration = audioHeader.getTrackLength();//时长

            music = new Music(songname, artist, album, duration, filePath);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return music;
    }
}


 

实验结果:

 4、改进代码

在运行上述代码后发现,基本上中文歌曲的歌名和歌手名会为空。

下列的代码对刚刚发现的bug,进行了修改,经过测试可以正常运行。

public Music getSongInfo(String filePath) {

        Music music = null;

        try {

            MP3File mp3File = (MP3File) AudioFileIO.read(new File(filePath));
            MP3AudioHeader audioHeader = (MP3AudioHeader) mp3File.getAudioHeader();

            String songname = mp3File.getID3v2Tag().frameMap.get("TIT2").toString();//歌名
            String artist = mp3File.getID3v2Tag().frameMap.get("TPE1").toString();//歌手
            String album = mp3File.getID3v2Tag().frameMap.get("TALB").toString();//专辑
            int duration = audioHeader.getTrackLength();//时长

            music = new Music(reg(songname), reg(artist), reg(album), duration, filePath);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return music;
}

测试发现songname,artist,album等,字符串会变成了“text = xxxx "

通过reg()函数处理了可以去掉。

//去除不必要的字符串
private String reg(String input) {

    return input.substring(input.indexOf('"') + 1, input.lastIndexOf('"'));
}

 

ps:如有疑问,可以通过留言,向我提问,我们共同学习。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_38500325/article/details/84776454

智能推荐

【Redis】1.Redis入门简介以及基本操作命令_redis入门基本操作_sdfreregtrh的博客-程序员宅基地

学习资料https://www.bilibili.com/video/BV1CJ411m7Gc?p=6问题的抛出出现的问题:海量用户高并发罪魁祸首——关系型数据库:性能瓶颈:磁盘IO性能低下扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群解决思路降低磁盘IO次数,越低越好 —— 内存存储去除数据间的关系,越简单越好 —— 不存储关系,仅存储数据Nosql简介NoSQL:即Not-OnlySQL(泛指非关系型的数据库),作为关系型数据库的补充。作用:应用对于海量用_redis入门基本操作

运算放大器的噪声计算(一)-程序员宅基地

近期 整理了关于运放噪声的一些理论与计算方法,如下:1、热噪声电压计算公式  由于运动幅度会随着温度的上升而上升,热噪声的幅度也会跟随温度上升,热噪声均方根RMS(root meam square),可以表示如下:                       (1)其中:en 表示RMS噪声电压 ..._热噪声计算公式

Microsoft Visual C++ 2010 Express调试出错_henauchin的博客-程序员宅基地

问题描述:LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 1.单击菜单栏中的项目-属性。 2.点击配置属性,清单工具,输入输出,嵌入式菜单,将是改成否,点击确定保存。 3.重新调试。...

linux du -sh df -a,df -h和du -sh显示的磁盘空间不一致分析_地精工效学者的博客-程序员宅基地

在Linux下查看磁盘空间使用情况,最常使用的就是du和df了。然而两者还是有很大区别的,有时候其输出结果甚至非常悬殊。1. 如何记忆这两个命令du -Disk Usagedf -Disk Free2. df 和du 的工作原理2.1 du的工作原理du命令会对待统计文件逐个调用fstat这个系统调用,获取文件大小。它的数据是基于文件获取的,所以有很大的灵活性,不一定非要针对一个分区,可以...

如何给金溢RSU配路网_aFakeProgramer的博客-程序员宅基地

如何给RSU配路网一、路网数据采集:利用车载单元OBU的GPS定位模块在特定的路段,选取两个点,一个设定为起点,一个终点(一般大概300~400米左右)中间不能有实体将RSU的信号遮挡。配置的时候,将定位模块放在车顶最中间的位置,车停在道路中间,(下车查看,GPS定位模块大致和路的中心线在一条直线上。)在obu的home目录下输入gpsmon命令,可以读出GPS数据。..._金溢rsu

转自 https://www.digitalocean.com/community/articles/how-to-create-a-ssl-certificate-on-nginx-for-cent_livesguan的博客-程序员宅基地

How To Create a SSL Certificate on nginx for CentOS 6TAGGED IN: NGINX, CENT OSAbout Self-Signed CertificatesA SSL certificate is a way to encrypt a site's information and create a more s

随便推点

mybatis封装工具类创建sqlsession-程序员宅基地

package com.lmt.until;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import javax.annotation.Resource;im

【Rust日报】2021-10-09 安卓团队正式介绍 Android Rust_Rust语言中文社区的博客-程序员宅基地

【官方】安卓团队正式介绍 Android RustAndroid平台提供了对用Rust开发本地操作系统组件的支持。Android Rust 模块 :https://source.andro...

egrep,sort_egrep |sort_yqxuc的博客-程序员宅基地

egrep = grep -E 可以使用基本的正则表达外, 还可以用扩展表达式. 注意区别.扩展表达式:+ 匹配一个或者多个先前的字符, 至少一个先前字符.? 匹配0个或者多个先前字符.a|b|c 匹配a或b或c() 字符组, 如: love(able|ers) 匹配loveable或lovers.(..)(..)\1\2 模板匹配. \1代表前面第一个模板, \2代_egrep |sort

JSON全解析_json_array是全表扫吗_YingJunZou的博客-程序员宅基地

json和xml都是跨平台的解析语言,但是json相对于xml虽然可读性要差点但是其解析方式相对简单,有效数据多的特点广泛运用于安卓网络响应格式,而且安卓内部集成了json不需要再导入jar包,1.json格式1.1{“fistname”{“fistname”:"Brett",“Lastname”:"li"} 这是一个jsonObject,即整个{},其中包含的数据是以 键:值的方式存储的_json_array是全表扫吗

SI4中文乱码_tingyu522的博客-程序员宅基地

File->Reload as encoding…选择UTF-8Option->preference->Files->Default encoding选择Chinese GB18030 CP54936解决欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了

Markdown语法图文全面详解(10分钟学会)_markwodn 语法-程序员宅基地

目录1. 快捷键2. 基本语法2.1 字体设置斜体、粗体、删除线2.2 分级标题2.3 链接2.4 分割线2.5 代码块2.6 引用2.7 列表2.8 表格3. 常用技巧3.1 换行3.2 缩进字符3.3 特殊符号3.4 字体、字号与颜色3.5 链接的高级操作1.行内式2.参考式链接3.内容目录..._markwodn 语法

推荐文章

热门文章

相关标签