由于时间仓促,所以没有加过多的错误处理或检查,另外结构体、变量和字符串等没有动态定义,可能会导致严重的缓冲区错误,所以如果要当做一个项目来做的话,建议加上这些处理、检查,并动态分配内存。
虽然说这是写成了一个C++类,但是文件读写以及许多函数都是C中的。见代码吧!代码看起来比较简单,老规矩,下载地址在后面。
差点忘记说明了,这种实现比较不好暂停,若有好点子,欢迎回复。谢谢!
#include <stdio.h>
#include <windows.h>
typedef struct
{
unsigned int time;
char data[40];
}LineData;
class CLrc
{
public:
BOOL Open( LPTSTR FileName );
void Close();
BOOL GetTitle( LPTSTR Title ); // 未实现
BOOL GetAlbum( LPTSTR Album ); // 未实现
BOOL GetArtist( LPTSTR Artist ); // 未实现
BOOL GetEditor( LPTSTR Editor ); // 未实现
BOOL ReadLine( LPTSTR Data );
CLrc()
{
memset( LrcFile, 0, 128 );
ldpoint = 0;
}
~CLrc()
{
if( hLrcFile != NULL )
{
fclose( hLrcFile );
}
}
// private:
FILE *hLrcFile;
char LrcFile[128];
LineData ld[100];
int ldpoint;
void DelCRLF( char *Data );
void Sort();
int Findch( const char *str, unsigned char ch );
int GetTime( const char *line );
void ResolveLine( const char *line );
void GetLineData( const char *line, char *data );
};
// 打开文件
BOOL CLrc::Open( LPTSTR FileName )
{
FILE *fp;
fp = fopen(FileName, "r");
if( fp == NULL )
{
return FALSE;
}
hLrcFile = fp;
return TRUE;
}
// 关闭文件
void CLrc::Close()
{
if( hLrcFile != NULL )
{
fclose( hLrcFile );
}
}
// 获得行的歌词
// 例如,[00:00.01]abc,该函数将获取到的"abc"保存到data中
void CLrc::GetLineData( const char *line, char *data )
{
int i = 0,
j = 0,
len;
if( strcmp( line, "" ) )
{
len = strlen( line );
i = len;
while( line[i] != ']' && i > 0 )
{
i--;
}
for( j = i + 1, i += 1; j <= len; j++ )
{
data[j - i] = line[j];
}
}
}
// 读取下一行数据
BOOL CLrc::ReadLine( char *line )
{
char Line[100];
memset( Line, 0, 100 );
if( feof( hLrcFile ) || fgets( Line, 100, hLrcFile) == NULL )
{
return FALSE; // 表示文件结束
}
DelCRLF( Line );
strcpy( line, Line );
return TRUE; // 正常
}
// 删除Data中的空格
void CLrc::DelCRLF( char *Data )
{
int i = 0;
int len = strlen( Data );
for( ; i < len; i++ )
{
if( Data[i] == 0x0D || Data[i] == 0x0A )
{
int j = i;
for( ; j < len ; j++ )
{
Data[j] = Data[j + 1];
}
}
}
}
// Findch用于检测ch在str中出现的次数
int CLrc::Findch( const char *str, unsigned char ch )
{
int i = strlen( str );
int quan = 0;
while( i-- )
{
if( str[i] == ch )
{
quan++;
}
}
return quan;
}
// 获得歌词时间
int CLrc::GetTime( const char *line )
{
int min = 0,
sec = 0,
ms = 0;
if(Findch(line, '.') == 0)
{
sscanf( line, "[%d:%d]", &min, &sec );
}
else
{
sscanf( line, "[%d:%d.%d]", &min, &sec, &ms );
}
return (min * 6000 + sec * 100 + ms );
}
// 解析每一行的数据,存入结构
void CLrc::ResolveLine( const char *line )
{
char str[100];
int i = 0,
j = 0,
last = 0;
strcpy( str, line );
if (Findch(str, '[') != Findch(str, ']') ) // 检测正确性
{
return;
}
for (i = 0; i <= strlen(str); i++ )
{
if (str[i] == ']')
{
char buf[50] = "";
int t = 0;
for (j = last; j <= i; j++ )
{
buf[t++] = str[j];
}
ld[ ldpoint ].time = GetTime( buf ) * 10;
GetLineData( line, ld[ldpoint].data);
ldpoint++;
i++;
last = i;
}
}
}
// 将结构中所有歌词排序,冒泡排序
void CLrc::Sort()
{
int i = 0, j;
for( ; i < ldpoint - 1; i++ )
{
for( j = i; j < ldpoint - i; j++ )
{
if( ld[j].time > ld[j + 1].time )
{
LineData t;
t = ld[j];
ld[j] = ld[j + 1];
ld[j + 1] = t;
}
}
}
}
调用方式:
int main()
{
CLrc lrc;
if( lrc.Open("J:\\lrc2.lrc") == FALSE )
{
printf( "无法打开歌词文件!\n" );
return 0;
}
while( true )
{
char line[100] = "";
if( !lrc.ReadLine( line ) ) // 读完了
{
break;
}
if( strcmp( line, "" ) )
{
lrc.ResolveLine( line ); // 解析数据
}
}
lrc.Close(); // 关闭文件句柄
lrc.Sort(); // 排序
if( lrc.ldpoint )
{
Sleep( lrc.ld[0].time );
printf( "%s\n", lrc.ld[0].data ); // 输出第一行
for( int i = 1; i < lrc.ldpoint; i++ )
{
Sleep( lrc.ld[i].time - lrc.ld[i - 1].time );
printf( "%s\n", lrc.ld[i].data );
}
}
return 0;
}