只提供对基本属性的读取(请参阅 MP3 的 ID3v1)。
/* 读取ASF(WMA、WMV)标签 */ public static MusicTagEntity ReadASFTag(String path) { try { char[] WMAHead = { 0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }; // WMA头部标识 char[] StandardHead = { 0x33, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }; // 标准TAG头部标识 char[] ExtendHead = { 0x40, 0xA4, 0xD0, 0xD2, 0x07, 0xE3, 0xD2, 0x11, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50 }; // 扩展TAG头部标识 String[] StandardHeadString = { "33", "26", "B2", "75", "8E", "66", "CF", "11", "A6", "D9", "00", "AA", "00", "62", "CE", "6C" }; // 标准TAG头部标识 String[] ExtendHeadString = { "40", "A4", "D0", "D2", "07", "E3", "D2", "11", "97", "F0", "00", "A0", "C9", "5E", "A8", "50" }; // 扩展TAG头部标识 MusicTagEntity mt = new MusicTagEntity(); File f = new File(path); InputStream is = new BufferedInputStream(new FileInputStream(f)); BufferedReader br = new BufferedReader(new InputStreamReader(is, "ISO-8859-1")); // 头部需要用ASCII编码 // 读取头部判断是否为WMA文件 char[] buf = new char[16]; br.read(buf); if (Arrays.equals(buf, WMAHead)) {// 是WMA br.read(buf = new char[14]); // 跳过无用的8+6字节 br.read(buf = new char[16]); // 确定标签类型的头 // 需要判断这里是先扩展再标准还是先标准再扩展 if (Arrays.equals(buf, ExtendHead)) {// 扩展 br.read(buf = new char[8]); // 再次放过8字节(此处无用的8字节标志位) br.read(buf = new char[2]); // 扩展标签的总个数 int ExtendCount = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 for (int i = 0; i < ExtendCount; i++) { br.read(buf = new char[2]); // 扩展名称长度 int FiledNameLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[FiledNameLength]); // 读取扩展名称 String strFieldName = Common.UnicodeCharToString(buf); br.read(buf = new char[2]); // Flag,暂时不用 br.read(buf = new char[2]); // 扩展字段长度 int FiledLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[FiledLength]); // 读取扩展字段 if (strFieldName.equals("WM/TrackNumber")) mt.setTrack(Common.UnicodeCharToString(buf)); if (strFieldName.equals("WM/Track")) mt.setTrack(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/AlbumArtist")) mt.setArtist(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/AlbumTitle")) mt.setAlbum(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/Year")) mt.setYear(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/Genre")) mt.setGener(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/WM/GenreID")) mt.setGener(Common.UnicodeCharToString(buf)); } // 开始读取标准头 do {// 跳过空白字符 br.read(buf = new char[1]); } while ((int) buf[0] == 0); boolean IsStandartHeader = true; // 是否包含标准头部信息 if (Integer.toHexString((int) buf[0]).equals(StandardHeadString[0])) { for (int i = 1; i <= 15; i++) { br.read(buf = new char[1]); String strHex = Integer.toHexString((int) buf[0]).toUpperCase(); if (strHex.length() == 1) strHex = "0" + strHex; if (!strHex.equals(StandardHeadString[i])) { IsStandartHeader = false; break; } } if (IsStandartHeader) {// 找到标准头 br.read(buf = new char[8]); // 8字节无效内容 br.read(buf = new char[2]); // 标题长度 int TitleLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[2]); // 艺术家长度 int ArtistLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[2]); // 版权长度 int CopyrightLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[2]); // 备注长度 int CommentLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[2]); // 2字节无效内容 // 读取标题 br.read(buf = new char[TitleLength]); mt.setTitle(Common.UnicodeCharToString(buf)); // 读取艺术家 br.read(buf = new char[ArtistLength]); if (mt.getArtist().equals("")) // 如果扩展属性中没有此信息,则采用 mt.setArtist(Common.UnicodeCharToString(buf)); br.read(buf = new char[CopyrightLength]); // 跳过版权说明 // 读取备注 br.read(buf = new char[CommentLength]); mt.setComment(Common.UnicodeCharToString(buf)); } } } else if (Arrays.equals(buf, StandardHead)) {// 标准 br.read(buf = new char[8]); // 8字节无效内容 br.read(buf = new char[2]); // 标题长度 int TitleLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[2]); // 艺术家长度 int ArtistLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[2]); // 版权长度 int CopyrightLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[2]); // 备注长度 int CommentLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[2]); // 2字节无效内容 // 读取标题 br.read(buf = new char[TitleLength]); mt.setTitle(Common.UnicodeCharToString(buf)); // 读取艺术家 br.read(buf = new char[ArtistLength]); mt.setArtist(Common.UnicodeCharToString(buf)); br.read(buf = new char[CopyrightLength]); // 跳过版权说明 // 读取备注 br.read(buf = new char[CommentLength]); mt.setComment(Common.UnicodeCharToString(buf)); // 开始读取扩展头 do {// 跳过空白字符 br.read(buf = new char[1]); } while ((int) buf[0] == 0); boolean IsExtendHeader = true; // 是否包含标准头部信息 if (Integer.toHexString((int) buf[0]).equals(ExtendHeadString[0])) { for (int i = 1; i <= 15; i++) { br.read(buf = new char[1]); String strHex = Integer.toHexString((int) buf[0]).toUpperCase(); if (strHex.length() == 1) strHex = "0" + strHex; if (!strHex.equals(ExtendHeadString[i])) { IsExtendHeader = false; break; } } if (IsExtendHeader) {// 找到扩展头 br.read(buf = new char[8]); // 再次放过8字节(此处无用的8字节标志位) br.read(buf = new char[2]); // 扩展标签的总个数 int ExtendCount = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 for (int i = 0; i < ExtendCount; i++) { br.read(buf = new char[2]); // 扩展名称长度 int FiledNameLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[FiledNameLength]); // 读取扩展名称 String strFieldName = Common.UnicodeCharToString(buf); br.read(buf = new char[2]); // Flag,暂时不用 br.read(buf = new char[2]); // 扩展字段长度 int FiledLength = Integer.valueOf(Common.DecodeUnicodeHex(buf), 16); // 转换成数值 br.read(buf = new char[FiledLength]); // 读取扩展字段 if (strFieldName.equals("WM/TrackNumber")) mt.setTrack(Common.UnicodeCharToString(buf)); if (strFieldName.equals("WM/Track")) mt.setTrack(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/AlbumArtist")) mt.setArtist(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/AlbumTitle")) mt.setAlbum(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/Year")) mt.setYear(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/Genre")) mt.setGener(Common.UnicodeCharToString(buf)); else if (strFieldName.equals("WM/WM/GenreID")) mt.setGener(Common.UnicodeCharToString(buf)); } } } } br.close(); is.close(); return mt; } else {// 不是ASF格式 br.close(); is.close(); return null; } } catch (Exception e) { e.printStackTrace(); return null; } }
相关的字符编码转换方法: /* 十六进制UnicodeChar转String */ public static String UnicodeCharToString(char[] Char) { String strTemp = ""; for (int i = 1; i < Char.length; i += 2) { String s1 = Integer.toHexString((int) Char[i]); String s2 = Integer.toHexString((int) Char[i - 1]); // 长度不足补全 if (s1.length() == 1) s1 = "0" + s1; if (s2.length() == 1) s2 = "0" + s2; strTemp += s1 + s2; } return UnicodeToString(strTemp).trim(); }
/* 将十六进制Unicode字符串转为汉字(将双字节转为单个字符) */ public static String UnicodeToString(String Hex) { String enUnicode = null; String deUnicode = null; for (int i = 0; i < Hex.length(); i++) { if (enUnicode == null) enUnicode = String.valueOf(Hex.charAt(i)); else enUnicode = enUnicode + Hex.charAt(i); if (i % 4 == 3) { if (enUnicode != null) { if (deUnicode == null) deUnicode = String.valueOf((char) Integer.valueOf(enUnicode, 16).intValue()); else deUnicode = deUnicode + String.valueOf((char) Integer.valueOf(enUnicode, 16).intValue()); } enUnicode = null; } } return deUnicode; }
/* 倒序排列十六进制Unicode(用以计算该字节标识的数值) */ public static String DecodeUnicodeHex(char[] Char) { String strTemp = ""; boolean CouldContinue = true; for (int i = Char.length - 1; i >= 0; i--) { String strHex = Integer.toHexString((int) Char[i]); if (strHex.length() == 1) strHex = "0" + strHex; if (strHex.equals("00") && CouldContinue) continue; else { strTemp += strHex; CouldContinue = false; } } return strTemp; }
此外还需要一个用于接收信息的类(MusicTagEntity.java): package *; //请自行填写 public class MusicTagEntity { private String Album = ""; // 专辑名称 private String Title = ""; // 歌曲标题 private String Gener = ""; // 流派 private String Artist = ""; // 艺术家 private String Year = ""; // 年份 private String Track = ""; // 音轨号 private String Lyric = ""; // 歌词 private String Comment = ""; // 备注 public String getAlbum() { return Album; } public void setAlbum(String album) { Album = album; } public String getTitle() { return Title; } public void setTitle(String title) { Title = title; } public String getGener() { return Gener; } public void setGener(String gener) { Gener = gener; } public String getArtist() { return Artist; } public void setArtist(String artist) { Artist = artist; } public String getYear() { return Year; } public void setYear(String year) { Year = year; } public String getTrack() { return Track; } public void setTrack(String track) { Track = track; } public String getLyric() { return Lyric; } public void setLyric(String lyric) { Lyric = lyric; } public String getComment() { return Comment; } public void setComment(String comment) { Comment = comment; } }