首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

黑马软件工程师_Mp3播放器之对lrc歌词文件的处理

2013-03-01 
黑马程序员_Mp3播放器之对lrc歌词文件的处理? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?------- android培训

黑马程序员_Mp3播放器之对lrc歌词文件的处理

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?------- android培训、java培训、期待与您交流! ----------

上一篇博客主要是讲了些mp3播放的后台service的播放情况,当时还重点了歌词的显示。后来发现还欠缺了一块内容才算完成,我打算在这里补充完整。过程是这样的,当我们拿到一个lrc文件,这个lrc文件就是网上很流行的lrc格式的歌词文件。这样处理它呢?这样处理的合合适适让它在MP3播放的activity中显示相应时间点的歌词呢?

?

我们的原理是这样的,我们所以在编写的lrc文件的时候都必须遵照一些约定俗成的格式,这样方便我们这些编写音乐播放软件的人处理lrc文件。我们先来看一幅图,
黑马软件工程师_Mp3播放器之对lrc歌词文件的处理
?

?

?

粗略看一下这个普通的lrc文件之后,我们是这样处理的建立一个LinkedHashMap<Long, String>类型的对象后,将前面的时间[00:06.09]作为long型的key放到这个map中,其歌词内容“想约在一个适合聊天的下午”作为这个[00:06.09]的key的值放到map中。这样我们就可以方便的根据是时间显示歌词了。

?

我们从代码来完整的看一篇如果进行的。

首先我们要创建一个lrc的类,这个类有一些属性:歌名啊,作者啊,歌词内容等等,还要设置set和get方法,和复写 toString()的方法(为什么我再想想,反正我经常见到)

package com.music.mp3;import java.util.LinkedHashMap;public class Lrc {private String title;private String singer;private String album;private String lrcEditer;private LinkedHashMap<Long,String> content;public Lrc() {super();}public Lrc(String title, String singer, String album,String lrcEditer, LinkedHashMap<Long, String> content) {super();this.title = title;this.singer = singer;this.album = album;this.lrcEditer = lrcEditer;this.content = content;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getSinger() {return singer;}public void setSinger(String singer) {this.singer = singer;}public String getAlbum() {return album;}public void setAlbum(String album) {this.album = album;}public String getLrcEditer() {return lrcEditer;}public void setLrcEditer(String lrcEditer) {this.lrcEditer = lrcEditer;}public LinkedHashMap<Long, String> getContent() {return content;}public void setContent(LinkedHashMap<Long, String> content) {this.content = content;}@Overridepublic String toString() {return "LrcInfo [album=" + album +  ", lrcEditer=" + lrcEditer + ", singer=" + singer+ ", title=" + title +", content=" + content+ "]";}}

?其他处理过程如下:

?

1.拿到歌词lrc文件所在地点

String path=MainActivity.SDPath+"mp3/"+Mp3PlayerActivity.m.getMp3_name()+".lrc";

2、从这个文件读取资料到内存,打开一个输入流

InputStream inputStream=null;

inputStream = new FileInputStream(path);

3、建立一个对这个文件处理的对象,并且把输入流交给这个对象的方法,进行处理。

Lrc lrc_result=null;//这个是等下把处理结果交给返回给别人的。

LrcProcessor p=new LrcProcessor();

lrc_result=p.process(inputStream);

4、LrcProcessor 类型的process()方法进行处理的过程,处理的结果返回有一个lrc类型的对象l,具备lrc类型的想要的属性。

package com.music.lrc;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.util.LinkedHashMap;import java.util.regex.Matcher;import java.util.regex.Pattern;import com.music.mp3.Lrc;public class LrcProcessor {//歌词对象Lrc l=null;//歌词对应毫秒值Long lrcTime=null;//对应显示的歌词String content=null;    //用户保存所有的歌词和时间点信息间的映射关系的Map    private LinkedHashMap<Long, String> maps = new LinkedHashMap<Long, String>();    public  Lrc process(InputStream in){    InputStreamReader re = null;//声明一个对输入流的reader对象try {re = new InputStreamReader(in,"GB2312");//reader对象读输入流,后一个参数是charsetName:identifies the character converter to use.我的理解就是不同编码 } catch (UnsupportedEncodingException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}    BufferedReader reader=new BufferedReader(re);//声明缓冲池,这是常规处理    String temp=null;    l=new Lrc();//这个是等下要返回的对象,一个lrc类型的文件用于在播放的service里面调用    try {while((temp=reader.readLine())!=null){//用temp一行一行的去读  setLrc(temp);//每读一次,就用一次这个setLrc文件的方法}l.setContent(maps);//将歌词的时间点(键)和歌词内容(值)这样一个maps交给l这个lrc类型的对象。(别的东西会对其处理,这里我们不要关心别的方法要对这个文件做什么)} catch (IOException e) {return null;}    return l;//返回给调用这个函数的对象的信息    }    public void setLrc(String str){    if (str.startsWith("[ti:")) {//以这个开头就是曲目    String title = str.substring(1, str.length() - 1); //所有的歌曲曲目都是以[ti: 开头和]结尾,那么这样做是正确的。但是为什么从第一个开始读,而不是从第5个呢    //System.out.println("title--->" + title); //验证歌词读对了没有   l.setTitle(title); }// 取得歌手信息   else if (str.startsWith("[ar:")) {        String singer = str.substring(1, str.length() - 1);        //System.out.println("singer--->" + singer);        l.setSinger(singer);    }// 取得专辑信息  else if (str.startsWith("[al:")) {     String album = str.substring(1, str.length() - 1);    //    System.out.println("album--->" + album);        l.setAlbum(album);   }else if (str.startsWith("[by:")) {     String lrcEditer = str.substring(1, str.length() - 1);      //  System.out.println("album--->" + album);        l.setLrcEditer(lrcEditer); //如果上面的都不是,那么肯定是歌曲内容了。}else{// 设置正则规则   String reg = "\\[(\\d{2}:\\d{2}\\.\\d{2})\\]";// 编译   compile的意思就是编译,所以就是用reg这个规则来编译出一个模式Pattern pattern = Pattern.compile(reg);// 出了模式最后再用其与传入的str去匹配。注意,str是一行一行读出来的结果Matcher matcher = pattern.matcher(str);//返回的是Matcher对象,再通过该对象的find()方法就可以查询是否匹配了。if(matcher.find()){String msg=matcher.group();//如何记录对应的时间呢,Matcher的group(int i)返回匹配字符,并前后剔除i个字符。当然这里为0String timeStr=msg.substring(1, msg.length()-1);//这是为了剔除时间前后的[]lrcTime=parseTime(timeStr);//我们把时间转化为毫秒,因为在mp3播放的service里面我们都是以毫秒为单位。这样方便比较和操作//下一句,我们用]作为分隔符,将一行内容"[03:07.77]我想哭 不敢哭"用]分隔后就会得到s[0]就是“[03:07.77” s[1]就是”我想哭 不敢哭“.String[] s=str.split("\\]");//如果用“.”作为分隔的话,必须是如下写法:String.split("\\."),这样才能正确的分隔开,不能用String.split(".");“.”和“|”都是转义字符,必须得加"\";if(s.length>=2){content=s[1];//用]来分割后,s[0]就是时间。而s[1]就是歌词内容maps.put(lrcTime, content);//设置键值对}}}    }    public Long parseTime(String timeStr){//将时间转换为毫秒的函数String s[]=timeStr.split(":");int min=Integer.parseInt(s[0]);    String ss[]=s[1].split("\\.");    int sec=Integer.parseInt(ss[0]);    int mil=Integer.parseInt(ss[1]);    //这样看来最后返回的毫秒数哦    return min*60*1000+sec*1000+mil*10L;//此处的L就相当于把int转换为Long}}

?最后,我想再对其中的正则表达式再做一个说明。我们对[02:31.72]这样一个格式的排序写出了如下的正则表达式:

\\[(\\d{2}:\\d{2}\\.\\d{2})\\]

其中\\是针转义字符用的。或者说在正则表达式中,"."本来就有特殊的含义了,如果我要用匹配一个真正的“.”,就要使用“\\.”告诉这个正则表达式的算法,我们要得是真正的“.”。显然其中“:”在正则表达式中没有含义,所以我们直接使用“:”就可以了。

其中,d{2}表示,是一个2位数的数字

其中()框起来的部分表示,我们要调用String msg=matcher.group();来获取这()内的内容。在这里,我们是获取其中的时间之后再对其处理改为毫秒

?

好了,对此,我相信我对歌词信息处理和正则表达式啊之类的理解有加深了。

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ------- android培训、java培训、期待与您交流! ----------

热点排行