使用第三方Java类库jaudiotagger完成Flac音频文件metadata(元数据)的读和修改

  最近需要使用Java Swing做个读写Flac格式音频文件的小GUI工具,虽然Mp3tag完全可以完成Flac的读写(编辑)任务,但是为了简化工作流程(编辑Flac信息后调用其它系统的接口完成部分信息上传等功能),需要开发一个集成类似Mp3tag功能和额外功能于一体的小工具。

  开发前的思考~~,“用JDK提供的IO(NIO)读写Flac?...”,“Flac的格式?...”,“一直潜心于JavaWeb和服务端接口开发...几乎没做过Java的GUI(Swing/AWT)!...”。。

  后来,在网上Google了一下是否有第三方专门处理音频文件(包括MP3、ape等等)的Java类库可以使用:结果用中文关键字检索很难找到满意的答案,最后在Stack
Overflow搜索到一个标题为“Reading metadata from FLAC files with
Java
”的Answer中找到了答案“Try using JAudiotagger. It supports MP3, MP4, Ogg
Vorbis, FLAC and WMA, and it has limited support for WAV and Real.”,接着,下载jar包,或者使用Maven构建工程的话,添加dependency即可。

<dependency>
<groupId>org</groupId>
<artifactId>jaudiotagger</artifactId>
<version>2.0.3</version>
</dependency>

  其实,在读写Flac文件之前,还是要先了解Flac是什么...Free Lossless Audio
Codec
-自由无损音频压缩编码...(貌似目前越来越流行无损音乐,无论是硬件播放器还是音频的高保真文件格式,或者本来就流行,奈我从未发现~~

  Wiki 
 官网 
 Flac的格式

  然后就是查看JAudiotagger API,编写代码,就简单多了...

  此文不对Flac中的每一个Tag信息进行英-中文对照说明,如果在音乐技术方面有深入研究的朋友可以私下交流沟通或有更好的网站方便提供一下,不胜感激~~PS:可以根据Tag映射中的英文key与Mp3tag中文版对照,或许可以找到答案。。。

  下面说明一下读取和写入(编辑)Tag信息的一般步骤及可能出现的困惑或卡壳(Stuck):

  1,阅JAudiotagger API知,使用FlacFileReader对象的read方法读取一个Flac文件,返回一个AudioFile(接口)类型的对象(实现了该接口的类的实例),再通过AudioFile中的方法getAudioHeadergetTag分别获得AudioHeader(接口)类型的对象和FlacTag类(实现了Tag接口)的对象。

  2,
利用获得的AudioHeader和FlacTag的对象即可获得想要的元数据(Metadata)信息,包括采样率(SampleRate)、制作格式或制作技术(Format)、单曲名(TITLE)、单曲艺术家(ARTIST)、专辑名(ALBUM)、专辑艺术家(ALBUM_ARTIST)、音轨号(TRACK)、语言(LANGUAGE)、版权方(COPYRIGHT)等等,使用FlacTag对象的getFirstArtwork方法可以获得图片。

  3,关于FlacTag中的Tag信息的Key值,有三种情况,一个是枚举FieldKey中的Key,另一个是FieldKey中没有的但是Tag映射表中有的Key;在读取Key对应的value值时,有两个重载的方法:getFirst(FieldKey id) 和getFirst(java.lang.String id),后面的方法包含了Tag映射中所有的key,当然也包括FieldKey枚举中的Key;最后一个就是Tag映射表中没有的,也就是自定义的key。

  获取单曲名称时,两个方法都可以,如下:

tag.getFirst("TITLE")
tag.getFirst(FieldKey.TITLE)

  但是获取版权方Copyright(flac中对应的key是COPYRIGHT,可以从Tag映射表中查到),但是FieldKey的枚举中没有(这个可以通过修改JAudiotagger源代码在枚举里面加上需要的key,不过完全没必要,JAudiotagger也只是把主要的可能比较重要比较常用的、一般Flac文件中都有的key放到枚举里面,通过重载的方法只要传入key的字符串id参数即可),像Copyright只好使用tag.getFirst("COPYRIGHT")方法读取版权信息。

 4,在修改Tag信息时,也是有两个方法,setField(FieldKey genericKey, java.lang.String value) 和setField(java.lang.String vorbisCommentKey, java.lang.String value) ,原因同3,像Copyright这样的Tag信息只好使用tag.setField("COPYRIGHT", "XX唱片公司");了。
 修改单曲名时,两个方法都可以,如下:

tag.setField(FieldKey.TITLE, "让一切随风");
tag.setField("TITLE", "让一切随风");

  仔细一点会从API发现FlacTag对象有如下方法(判读一个Tag的key是否存在):

tag.hasField("COPYRIGHT")

  如果返回true,则读取时可能有版权信息,因为有可能只是在Flac文件中加了COPYRIGHT却没有设置值,没有值则返回"",不返回null;如果返回false,显然Flac文件中还没有COPYRIGHT;无论hasField方法返回的是true还是false,只要被判断的key在Tag映射表存在,都可以直接调用tag.setField("COPYRIGHT",
"XX唱片公司");方法为COPYRIGHT或者其它key设置值。

  5,3和4中讨论的Tag(FlacTag)信息中的key都是Tag映射中有的Key,如果想要自定义一个key,并为自定义的key设置值,且在下次读取该Flac文件时可以读出这个自定义key的值,就需要另外的方法addField(java.lang.String vorbisCommentKey,
java.lang.String value)
 ,例如自定义一个假设叫做ISTEST的key,如下:

tag.addField("ISTEST", "true");

  6, 再仔细一点就会发现,还有一个addField的重载方法,addField(FieldKey genericKey,
java.lang.String value)
 ,这是什么意思呢?如果执行

tag.addField("COPYRIGHT")又会怎样呢?蛮奇怪的,为什么读取Tag信息的时候是getFirst方法?为什么有个First呢?
  假设Flac文件中已经有TITLE和COPYRIGHT,然后再执行下面两条语句:

tag.addField(FieldKey.TITLE,"让一切随心");
tag.addField("COPYRIGHT","YY唱片公司");

通过调用tag.getVorbisCommentTag()方法,观察一下OGG Tag content的内容如下:

  如果分别调用getFirst方法去获取TITLE和COPYRIGHT的值,显然分别是“让一切随风”和“XX唱片公司”。

  7,4中所言可以为Tag映射表中存在的key,即使Flac文件中没有,也可以通过setField方法设置值,那么自定义的key可不可以呢?答案是肯定的,即可以使用setField为Flac文件添加一个自定义的Tag信息。

  通过API和代码测试,addField和setField的区别当然也很容易就会想到,addField会不断的create,而setField只在第一次设置值时发现key不存在才会create并设置值,否则只是改变value的值。

  8, 删除Tag信息,直接删除key即可,方法deleteField(FieldKey fieldKey) 和deleteField(java.lang.String id) ,这两个方法均会删除6中所add的所有相同key的Tag信息,表现就是删除后调用hasField方法返回false。

   9, API中还有createField以及对图片的获取、图片信息的添加修改如setField(Artwork artwork) 等,暂不叙述。

  10,
关于Tag信息修改后的保存到flac文件中去:在Tag信息通过setField方法修改后,使用FlacFileWriter对象的write方法将读出来的AudioFile对象“写回去”即可(flac文件只会改变set的key-value或者添加一个新的key或者删除相同的某个key及对应value,其它的信息不会丢失)。

 

时间: 2024-10-10 00:59:45

使用第三方Java类库jaudiotagger完成Flac音频文件metadata(元数据)的读和修改的相关文章

Java如何检查文件是否在服务器上被修改了?

在Java编程中,如何检查文件是否在服务器上被修改了? 以下示例显示如何检查文件是否在服务器上进行了修改. package com.yiibai; import java.net.URL; import java.net.URLConnection; public class FileModificationTime2 { public static void main(String[] argv) throws Exception { URL u = new URL("http://www.y

使用CocoaPods管理第三方开源类库

iOS开发中经常会用到许多第三方类库,比如AFNetworking.FMDB.JSONKit等等,使用CocoaPods这个工具就能很方便得对工程中用到的类库进行管理,包括自动下载配置以及更新. 首先需要下载安装CocoaPods,系统要求有ruby环境,至少OS X 10.9以后是自带ruby环境的(Python也自带了),使用"ruby -v"命令可以查看当前ruby版本. 配置过程如下: 1.ruby环境 不放心的话可以先确认下ruby环境,据说由于GFW的影响,大都把Ruby镜

java类库中的设计模式

原帖:http://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns 提问:我正在学习GoF的<设计模式>,想了解些它们在实际中的应用的样例. 大家能给我举一些使用设计模式的好样例吗?尤其是在Java类库中. 获得赞同最高的回答: 你能够通过Wikipedia对设计模式有个总体上的理解.Wikipedia上也提高了GoF所涉及到的模式.我这里总结一下,而且尽可能指出在JavaSE与JavaEE的API中是怎样

Atitit.&#160;衡量项目规模&#160;----包含的类的数量&#160;.net&#160;java类库包含多少类&#160;多少个api方法??

Atitit. 衡量项目规模 ----包含的类的数量 .net java类库包含多少类 多少个api方法?? 1 framework 4.5 (10万个api)1 2 Jdk8   57M1 3 Gialen项目2 4 播放器项目 3500个类2 5 Jquery 1.11 (api 305个)2 6 Wordpress 4.2   (函数api详单(约500个api)2 7 Html5  860个api2 7.1 Css2 8 Js  430个3 1 framework 4.5 (10万个ap

Android学习笔记(四四):第三方Java库的使用

Java有很多第三方库.Android的Dalvik虚拟器不完全是Java,也就是Android SDK和传统的SDK不完全一样,如果Java库兼容Android,则可被利用.Java库使用受限于下面因素: 目标平台:Java代码适配版本是否比Android基于的Java版本更高.是否用了Android不支持的Java SE的API,例如Swing.AWT图形. Size:为桌面或者服务器设计的Java代码不需要考虑存储和内存空间,Android需要,使用第三方Java代码,可能会是应用Size

java类库 collection与collections (转)

http://www.cnblogs.com/dashi/p/3597937.html Java中Collection和Collections的区别 1.java.util.Collection 是一个集合接口(集合类的一个顶级接口).它提供了对集合对象进行基本操作的通用接口方法.Collection接口在Java 类库中有很多具体的实现.Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set. Collection   ├List   │├

2016 年排名 Top 100 的 Java 类库

我们分析了GitHub中47,251个依赖,从中找出了排名前一百的Java类库,让我们看看谁在前面,谁在后面. 我们在漫长的周末的消遣方式就是浏览GitHub并且搜索流行的Java类库.我们决定把其中的乐趣与结果分享给你. 我们分析了GitHub中排名前3,862个项目中的47,251个导入语句,其中有12,059个Java类库被依赖.我们从这个列表中提取出前一百并把结果分享给你. 最受欢迎的前20个Java类库 和上次分析结果一致,junit依旧是GitHub中最受欢迎的类库.Java中的日志

词典的实现(3)--使用JAVA类库ArrayList实现Map数据结构

1,在词典的实现(2)-借助顺序表(数组)实现词典文章中使用了自定义的数组代替ArrayList,并实现了Map数据结构的基本功能.而借助JAVA类库ArrayList类的一些方法可以更加容易地实现Map. 2,实现思路如下 ArrayListDictionary.java 中定义了一个ArrayList的对象,该ArrayList对象用来存储Entry类的对象,而Entry类封装了(key,value).这样,利用ArrayList类的一些方法来间接地操作(key,value),从而实现各种词

学习使用Delphi for android 调用Java类库

http://blog.csdn.net/laorenshen/article/details/41148253 学习使用Delphi for android 调用Java类库 2014-11-15 18:36 1053人阅读 评论(0) 收藏 举报  分类: 安卓开发(27)  Android是一套非常优秀的移动端操作系统,Delphi Xe5中也能直接调用SDK中提供的各项API,但是delphi自己封装的AndroidAPI非常少,在安装目录的 source\rtl\android 中,而