从MP3中提取歌曲信息(C#)
2024-07-21 02:18:24
供稿:网友
从mp3中提取歌曲信息
一首mp3歌曲除了音乐信息外,还包含了如歌名、演唱者等信息,当我们用winamp软件听音乐时,播放清单就自动将这些信息读出来。大部分人都喜欢从网上下载音乐,但下载下来的mp3文件名都是文件上传系统自动取名的,和歌曲本身根本不相符,所以,给用户带来了很大的麻烦。但是,懒人有懒人的做法,我们何不自己写一个程序,将歌曲信息自动读出来并为mp3文件自动更名呢?
下面我就以c#为工具,把开发过程写出来。
一首mp3的额外信息存放在文件的最后面,共占128个字节,其中包括以下的内容(我们定义一个结构说明):
public struct mp3info
{
public string identify;//tag,三个字节
public string title;//歌曲名,30个字节
public string artist;//歌手名,30个字节
public string album;//所属唱片,30个字节
public string year;//年,4个字符
public string comment;//注释,28个字节
public char reserved1;//保留位,一个字节
public char reserved2;//保留位,一个字节
public char reserved3;//保留位,一个字节
}
所以,我们只要把mp3文件的最后128个字节分段读出来并保存到该结构里就可以了。函数定义如下:
/// <summary>
/// 获取mp3文件最后128个字节
/// </summary>
/// <param name="filename">文件名</param>
/// <returns>返回字节数组</returns>
private byte[] getlast128(string filename)
{
filestream fs = new filestream(filename,filemode.open,fileaccess.read);
stream stream = fs;
stream.seek(-128,seekorigin.end);
const int seekpos = 128;
int rl = 0;
byte[] info = new byte[seekpos];
rl = stream.read(info,0,seekpos);
fs.close();
stream.close();
return info;
}
再对上面返回的字节数组分段取出,并保存到mp3info结构中返回。
/// <summary>
/// 获取mp3歌曲的相关信息
/// </summary>
/// <param name = "info">从mp3文件中截取的二进制信息</param>
/// <returns>返回一个mp3info结构</returns>
private mp3info getmp3info(byte[] info)
{
mp3info mp3info = new mp3info();
string str = null;
int i;
int position = 0;//循环的起始值
int currentindex = 0;//info的当前索引值
//获取tag标识
for(i = currentindex;i<currentindex+3;i++)
{
str = str+(char)info[i];
position++;
}
currentindex = position;
mp3info.identify = str;
//获取歌名
str = null;
byte[] byttitle = new byte[30];//将歌名部分读到一个单独的数组中
int j = 0;
for(i = currentindex;i<currentindex+30;i++)
{
byttitle[j] = info[i];
position++;
j++;
}
currentindex = position;
mp3info.title = this.bytetostring(byttitle);
//获取歌手名
str = null;
j = 0;
byte[] bytartist = new byte[30];//将歌手名部分读到一个单独的数组中
for(i = currentindex;i<currentindex+30;i++)
{
bytartist[j] = info[i];
position++;
j++;
}
currentindex = position;
mp3info.artist = this.bytetostring(bytartist);
//获取唱片名
str = null;
j = 0;
byte[] bytalbum = new byte[30];//将唱片名部分读到一个单独的数组中
for(i = currentindex;i<currentindex+30;i++)
{
bytalbum[j] = info[i];
position++;
j++;
}
currentindex = position;
mp3info.album = this.bytetostring(bytalbum);
//获取年
str = null;
j = 0;
byte[] bytyear = new byte[4];//将年部分读到一个单独的数组中
for(i = currentindex;i<currentindex+4;i++)
{
bytyear[j] = info[i];
position++;
j++;
}
currentindex = position;
mp3info.year = this.bytetostring(bytyear);
//获取注释
str = null;
j = 0;
byte[] bytcomment = new byte[28];//将注释部分读到一个单独的数组中
for(i = currentindex;i<currentindex+25;i++)
{
bytcomment[j] = info[i];
position++;
j++;
}
currentindex = position;
mp3info.comment = this.bytetostring(bytcomment);
//以下获取保留位
mp3info.reserved1 = (char)info[++position];
mp3info.reserved2 = (char)info[++position];
mp3info.reserved3 = (char)info[++position];
return mp3info;
}
上面程序用到下面的方法:
/// <summary>
/// 将字节数组转换成字符串
/// </summary>
/// <param name = "b">字节数组</param>
/// <returns>返回转换后的字符串</returns>
private string bytetostring(byte[] b)
{
encoding enc = encoding.getencoding("gb2312");
string str = enc.getstring(b);
str = str.substring(0,str.indexof('/0') >= 0 ? str.indexof('/0') : str.length);//去掉无用字符
return str;
}
改名怎么办呢?我们按(演唱者)歌名 的格式对歌曲进行改名,程序如下:
/// <summary>
/// 更改文件名
/// </summary>
/// <param name="filepath">文件名</param>
/// <returns></returns>
private bool rename(string filepath)
{
if(file.exists(filepath))
{
mp3info mp3info = new mp3info();
mp3info = this.getmp3info(this.getlast128(filepath));//读出文件信息
mp3info.artist = this.deletenotvalue(mp3info.artist);
mp3info.title = this.deletenotvalue(mp3info.title);
if(mp3info.artist.trim().length==0)
{
mp3info.artist="未命名";
}
if(mp3info.title.trim().length==0)
{
mp3info.title="未知名歌曲";
}
try
{
//更名
file.move(filepath,filepath.substring(0,filepath.tolower().lastindexof("//")).trim() + "//" + "(" + mp3info.artist.trim() + ")" +mp3info.title.trim() + ".mp3");
return true;
}
catch(exception)
{
return false;
}
}
else
{
return false;
}
}
呵,思路就是这样了,如果有问题或者需要源码请发邮件至:[email protected]索取。