做之前,都没有想到读取MP3额外信息竟然如此简单,看来有时候技术真的就是一层玻璃纸,捅破了就没有什么秘密感.
类ExtractMusic:
public class ExtractMusic {
public static void main(String[] args) throws IOException {
//就用梁静茹的歌做个示例String path = new String("d://慢慢来比较快.mp3");
/** * RandomAccessFile(String name, String mode) * * name:指定文件,不用多说了 * mode:访问模式("r"、"rw"、"rws" 或 "rwd" ),"r"代表只读 */RandomAccessFile read = new RandomAccessFile(path, "r");
/** * public void seek(long pos) throws IOException * pos:文件指针偏移量 * MP3的最后128个字节用来存储额外信息,详情请看 * (http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm#MPEGTAG) */ read.seek(read.length()-128); //将文件指针定位到最后128个字节的位置,准备读取byte[] buffer = new byte[128]; //准备存储最后128个字节
/** * public final void readFully(byte[] b) throws IOException * b:从当前文件指针开始,将 b.length 个字节读到 b中 */read.readFully(buffer);
MusicInfo info = new MusicInfo(buffer);//用MusicInfo类来封装buffer的数据
if(info.isValid()){ //判断数据的合法性,以及封装数据
System.out.println("title:" + info.getTitle()); System.out.println("artist:" + info.getArtist()); System.out.println("album:" + info.getAlbum()); System.out.println("year:" + info.getYear()); System.out.println("comment:" + info.getComment()); //在MusicInfo中,虽然有genre的成员,但是并没有给其数据,所以输出为nullSystem.out.println(info.getGenre());
}
/** 输出: title:慢慢来比较快 artist:梁静茹 album:情歌没有告诉你 year:2010 comment:WWW.TOP100.CN 巨鲸音乐网 null */}
}
类MusicInfo:
public class MusicInfo {
private final String TAG = "TAG";
private String title; private String artist; private String album; private String year; private String comment; private String genre;private byte[] buffer = null;
public MusicInfo() {}public MusicInfo(byte[] buffer) {
this.buffer = buffer; //接受buffer
}
public boolean isValid() throws UnsupportedEncodingException{
/** http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm#MPEGTAG MP3格式最后128个字节存储方式, Sign Length (bytes) Position (bytes) Description A 3 (0-2) Tag identification. Must contain 'TAG' if tag exists and is correct. B 30 (3-32) Title C 30 (33-62) Artist D 30 (63-92) Album E 4 (93-96) Year F 30 (97-126) Comment G 1 (127) Genre 由于规定前3个字节是TAG,所以如果只想简单的校验数据,只需判断TAG是否存在就行了 */String flag = new String(this.buffer,0,3);
if(TAG.equals(flag)){ //如果存在,封装数据
/** 中文歌曲,而且额外信息中也包含中文,需要手动用gb18030编码,详情请看: http://baike.baidu.com/view/889058.htm */this.title = new String(this.buffer,3,30,"gb18030").trim();
this.artist = new String(this.buffer,33,30,"gb18030").trim();
this.album = new String(this.buffer,63,30,"gb18030").trim();
this.year = new String(this.buffer,93,4,"gb18030").trim();
this.comment = new String(this.buffer,97,30,"gb18030").trim();
/** 没有对genre成员赋值,因为这1个字节里面存的不是流派的直接值,类似于索引值 0 'Blues' 20 'Alternative' 40 'AlternRock' 60 'Top 40' 1 'Classic Rock' 21 'Ska' 41 'Bass' 61 'Christian Rap' 2 'Country' 22 'Death Metal' 42 'Soul' 62 'Pop/Funk' 3 'Dance' 23 'Pranks' 43 'Punk' 63 'Jungle' 4 'Disco' 24 'Soundtrack' ... ... 这里就不进行处理了 */ //this.genre = this.buffer[127]; return true;}
return false;}
public String getTitle() { return title;}
public String getArtist() { return artist;}
public String getAlbum() { return album;}
public String getYear() { return year;}
public String getComment() { return comment;}
public String getGenre() { return genre;}
}
