直接拿去用把,封装成类了,如有不解地方可以问我:
{------------------------------------------------------------------------------
Unit name: Mp3Tag
Author: Alex (zqw0117@sina.com)
Update date: 2004.8.7
History:
2005.3.6: 1.更改部分方法名
2.增加 EraseTag 方法
2004.8.7: 第一个版本完成,初步实现所有读写操作功能.
本单元实现对 mp3 后缀信息读取和写入的类。
------------------------------------------------------------------------------}
unit Mp3Tag;
interface
uses
SysUtils, Windows;
const
Mp3TagIdent = 'TAG';
type
TMp3Tag = record
Ident: array[0..2] of char;
Title: array[0..29] of char;
Artist: array[0..29] of char;
Album: array[0..29] of char;
Year: array[0..3] of char;
Comment: array[0..27] of char;
Reserved1: Byte;
Reserved2: Byte;
Reserved3: Byte;
end;
TMp3TagInfoError = (mfeOK, mfeNotMp3FileOrNotExists, mfeOpenFileError, mfeReadFileError,
mfeWriteFileError, mfeEraseFileError, mfeNoTagInfo);
TMp3TagInfo = class(TObject)
private
{ private declarations }
FMp3Tag: TMp3Tag;
FMp3FileName: string;
FModified: Boolean;
function AssureFileName(const AMp3FileName: string): Boolean;
procedure SetMp3FileName(const AValue: string);
function GetIdent: string;
function GetHasTag: Boolean;
function GetTitle: string;
function GetArtist: string;
function GetAlbum: string;
function GetYear: string;
function GetComment: string;
function GetReserved1: Byte;
function GetReserved2: Byte;
function GetReserved3: Byte;
procedure SetTitle(const AValue: string);
procedure SetArtist(const AValue: string);
procedure SetAlbum(const AValue: string);
procedure SetYear(const AValue: string);
procedure SetComment(const AValue: string);
procedure SetReserved1(const AValue: Byte);
procedure SetReserved2(const AValue: Byte);
procedure SetReserved3(const AValue: Byte);
protected
FLastError: TMp3TagInfoError;
public
{ Public declarations }
constructor Create(const AMp3FileName: string);
procedure ReadTag;
function WriteTag: Boolean;
function EraseTag: Boolean;
function GetLastErrorStr: string;
dynamic;
property HasTag: Boolean read GetHasTag;
property Mp3File: string read FMp3FileName write SetMp3FileName;
property Title: string read GetTitle write SetTitle;
property Artist: string read GetArtist write SetArtist;
property Album: string read GetAlbum write SetAlbum;
property Year: string read GetYear write SetYear;
property Comment: string read GetComment write SetComment;
property Reserved1: Byte read GetReserved1 write SetReserved1;
property Reserved2: Byte read GetReserved2 write SetReserved2;
property Reserved3: Byte read GetReserved3 write SetReserved3;
property Modified: Boolean read FModified write FModified;
property LastError: TMp3TagInfoError read FLastError;
end;
implementation
constructor TMp3TagInfo.Create(const AMp3FileName: string);
begin
FLastError := mfeOK;
FMp3FileName := AMp3FileName;
ReadTag;
end;
function TMp3TagInfo.AssureFileName(const AMp3FileName: string): Boolean;
begin
Result := (AMp3FileName <> '') and (FileExists(AMp3FileName)) and
(SameText(ExtractFileExt(AMp3FileName), '.mp3'));
end;
procedure TMp3TagInfo.ReadTag;
var
iFileHandle: Integer;
iReadLen: Integer;
begin
FillChar(FMp3Tag, SizeOf(FMp3Tag), #0);
//make sure the file name is *.mp3 & it exists
if not AssureFileName(FMp3FileName) then
begin
FLastError := mfeNotMp3FileOrNotExists;
Exit;
end;
iFileHandle := FileOpen(FMp3FileName, fmOpenRead or fmShareDenyWrite);
if (iFileHandle < 0) then
begin
FLastError := mfeOpenFileError;
Exit;
end;
try
FileSeek(iFileHandle, -SizeOf(FMp3Tag), 2);
iReadLen := FileRead(iFileHandle, FMp3Tag, SizeOf(FMp3Tag));
if (iReadLen < SizeOf(FMp3Tag)) then
begin
FLastError := mfeReadFileError;
FillChar(FMp3Tag, SizeOf(FMp3Tag), #0);
Exit;
end;
if HasTag then
begin
FLastError := mfeOK;
FModified := False;
end
else
begin
FLastError := mfeNoTagInfo;
FillChar(FMp3Tag, SizeOf(FMp3Tag), #0);
end;
finally
if (iFileHandle > 0) then
FileClose(iFileHandle);
end;
end;
procedure TMp3TagInfo.SetMp3FileName(const AValue: string);
begin
if (AValue <> FMp3FileName) then
begin
FMp3FileName := AValue;
ReadTag;
end;
end;
function TagArrayToStr(const A: Array of Char;
Index: Integer;
const Count: Integer): string;
var
C: Integer;
begin
Result := '';
C := 0;
while C < Countdo
begin
Result := Result + A[Index];
Inc(C);
Inc(Index);
end;
end;
function TMp3TagInfo.GetIdent: string;
begin
Result := TagArrayToStr(FMp3Tag.Ident, 0, 3);
end;
function TMp3TagInfo.GetHasTag: Boolean;
begin
Result := SameText(GetIdent, Mp3TagIdent);
end;
function TMp3TagInfo.GetTitle: string;
begin
Result := TrimRight(TagArrayToStr(FMp3Tag.Title, 0, 30));
end;
function TMp3TagInfo.GetArtist: string;
begin
Result := TrimRight(TagArrayToStr(FMp3Tag.Artist, 0, 30));
end;
function TMp3TagInfo.GetAlbum: string;
begin
Result := TrimRight(TagArrayToStr(FMp3Tag.Album, 0, 30));
end;
function TMp3TagInfo.GetYear: string;
begin
Result := TrimRight(TagArrayToStr(FMp3Tag.Year, 0, 4));
end;
function TMp3TagInfo.GetComment: string;
begin
Result := TrimRight(TagArrayToStr(FMp3Tag.Comment, 0, 28));
end;
function TMp3TagInfo.GetReserved1: Byte;
begin
Result := FMp3Tag.Reserved1;
end;
function TMp3TagInfo.GetReserved2: Byte;
begin
Result := FMp3Tag.Reserved2;
end;
function TMp3TagInfo.GetReserved3: Byte;
begin
Result := FMp3Tag.Reserved3;
end;
procedure StrToTagArray(var A: Array of Char;
const S: string;
const ArrayMaxLength: Integer);
var
aIndex, sIndex, strLen: Integer;
begin
aIndex := Low(A);
sIndex := 1;
strLen := Length(S);
while aIndex < ArrayMaxLengthdo
begin
if sIndex <= strLen then
A[aIndex] := S[sIndex]
else
A[aIndex] := #0;
Inc(aIndex);Inc(sIndex);
end;
end;
procedure TMp3TagInfo.SetTitle(const AValue: string);
begin
if Title <> Copy(AValue, 1, 30) then
begin
StrToTagArray(FMp3Tag.Title, AValue, 30);
FModified := True;
end;
end;
procedure TMp3TagInfo.SetArtist(const AValue: string);
begin
if Artist <> Copy(AValue, 1, 30) then
begin
StrToTagArray(FMp3Tag.Artist, AValue, 30);
FModified := True;
end;
end;
procedure TMp3TagInfo.SetAlbum(const AValue: string);
begin
if Album <> Copy(AValue, 1, 30) then
begin
StrToTagArray(FMp3Tag.Album, AValue, 30);
FModified := True;
end;
end;
procedure TMp3TagInfo.SetYear(const AValue: string);
begin
if Year <> Copy(AValue, 1, 4) then
begin
StrToTagArray(FMp3Tag.Year, AValue, 4);
FModified := True;
end;
end;
procedure TMp3TagInfo.SetComment(const AValue: string);
begin
if Comment <> Copy(AValue, 1, 28) then
begin
StrToTagArray(FMp3Tag.Year, AValue, 28);
FModified := True;
end;
end;
procedure TMp3TagInfo.SetReserved1(const AValue: Byte);
begin
if Reserved1 <> AValue then
begin
FMp3Tag.Reserved1 := AValue;
FModified := True;
end;
end;
procedure TMp3TagInfo.SetReserved2(const AValue: Byte);
begin
if Reserved2 <> AValue then
begin
FMp3Tag.Reserved2 := AValue;
FModified := True;
end;
end;
procedure TMp3TagInfo.SetReserved3(const AValue: Byte);
begin
if Reserved3 <> AValue then
begin
FMp3Tag.Reserved3 := AValue;
FModified := True;
end;
end;
function TMp3TagInfo.WriteTag: Boolean;
var
iFileHandle: Integer;
iFileAttr: Integer;
iReadLen: Integer;
bFailTurnbackTag: Boolean;
begin
Result := False;
bFailTurnbackTag := False;
//make sure the file name is *.mp3 & it exists
if not AssureFileName(FMp3FileName) then
begin
FLastError := mfeNotMp3FileOrNotExists;
Exit;
end;
iFileAttr := FileGetAttr(FMp3FileName);
try
FileSetAttr(FMp3FileName, faArchive);
iFileHandle := FileOpen(FMp3FileName, fmOpenWrite or fmShareDenyWrite);
if (iFileHandle < 0) then
begin
FLastError := mfeOpenFileError;
Exit;
end;
try
{
如果文件本身有 Tag 的话,就Seek到Tag位置重新写入,就是改写;
否则,就 Seek 到文件末尾,给 mp3 文件增加一个 Tag。
}
if HasTag then
FileSeek(iFileHandle, -SizeOf(FMp3Tag), 2)
else
begin
FileSeek(iFileHandle, 0, 2);
FMp3Tag.Ident := Mp3TagIdent;
// 由于没有 Ident ,写入的时候必须手工添加
bFailTurnbackTag := True;
end;
iReadLen := FileWrite(iFileHandle, FMp3Tag, SizeOf(FMp3Tag));
if (iReadLen < SizeOf(FMp3Tag)) then
begin
FLastError := mfeWriteFileError;
// 如果写入失败,将写入前手工添加的 Ident 去除
if bFailTurnbackTag then
StrToTagArray(FMp3Tag.Ident, '', 3);
Exit;
end;
FModified := False;
FLastError := mfeOK;
Result := True;
finally
if (iFileHandle > 0) then
FileClose(iFileHandle);
end;
finally
FileSetAttr(FMp3FileName, iFileAttr);
end;
end;
function TMp3TagInfo.GetLastErrorStr: string;
begin
case FLastError of
mfeNotMp3FileOrNotExists: Result := '文件不是 .mp3 扩展名,或文件不存在';
mfeOpenFileError: Result := '打开文件错误';
mfeReadFileError: Result := '读取文件失败';
mfeWriteFileError: Result := '写入文件失败';
mfeEraseFileError: Result := '擦除 Tag 失败';
mfeNoTagInfo: Result := '无 Tag 信息';
else
Result := '';
end;
end;
function TMp3TagInfo.EraseTag: Boolean;
var
iFileHandle: Integer;
iFileAttr: Integer;
bFailTurnbackTag: Boolean;
begin
Result := False;
if not AssureFileName(FMp3FileName) then
begin
FLastError := mfeNotMp3FileOrNotExists;
Exit;
end;
iFileAttr := FileGetAttr(FMp3FileName);
try
FileSetAttr(FMp3FileName, faArchive);
iFileHandle := FileOpen(FMp3FileName, fmOpenWrite or fmShareDenyWrite);
if (iFileHandle < 0) then
begin
FLastError := mfeOpenFileError;
Exit;
end;
try
{
检查是否有 Tag 信息,如果有才擦除
}
if HasTag then
begin
FileSeek(iFileHandle, -SizeOf(FMp3Tag), 2);
Result := SetEndOfFile(iFileHandle);
if Reuslt then
FLastError := mfeOK
else
FLastError := mfeEraseFileError;
ReadTag
end
else
FLastError := mfeNoTagInfo;
finally
if (iFileHandle > 0) then
FileClose(iFileHandle);
end;
finally
FileSetAttr(FMp3FileName, iFileAttr);
end;
end;
end.