Wave 文件的前 12 個字節可以這樣描述:
TRiff = record
ckId : DWord; {'RIFF'}
ckSize : DWord; {文件大小, 不包括前 8 個字節}
fccType : DWord; {'WAVE'}
end;
我們讀出文件的前 12 個字節進行判斷, 就基本可以確認它是不是 Wave 文件.
uses MMSystem, IOUtils; {這裡准備用 IOUtils.TFile.OpenRead 方便地建立文件流}
procedure TForm1.FormCreate(Sender: TObject);
var
riff: record ckId, ckSize, fccType: DWord; end; {可以同時定義結構並聲明結構變量}
begin
with TFile.OpenRead('C:\WINDOWS\Media\Windows XP 啟動.wav') do
begin
Read(riff, SizeOf(riff));
Free;
end;
if (riff.ckId = FOURCC_RIFF) and (riff.fccType = mmiOStringToFOURCC('WAVE',0)) then
ShowMessageFmt('這是個 Wave 文件, 其大小是 %d 字節', [riff.ckSize + 8]);
end;
還是把它寫成一個函數吧, 最好也別再引用 MMSystem 單元.
{如果是 Wave 文件則返回文件大小, 不是則返回 0}
function IsWave(FilePath: string): Integer;
function mmioFOURCC(Chr0,Chr1,Chr2,Chr3: AnsiChar): DWord;
begin
Result := DWORD(Chr0) + DWORD(Chr1) shl 8 + DWORD(Chr2) shl 16 + DWord(Chr3) shl 24;
end;
var
riff: record ckId, ckSize, fccType: DWord; end;
begin
Result := 0;
with TFileStream.Create(FilePath, fmOpenRead) do begin
Read(riff, SizeOf(riff));
Free;
end;
if (riff.ckId = mmioFOURCC('R', 'I', 'F', 'F')) and
(riff.fccType = mmioFOURCC('W', 'A', 'V', 'E')) then
Result := riff.ckSize + 8;
end;
依次道理, 也可以判斷一個 RIFF 文件具體是什麼格式.
{返回 RIFF 文件格式的函數, 如果不是 RIFF 文件, 則返回 'noneRIFF'}
function GetRiffType(FilePath: string): String;
function mmioFOURCC(Chr0,Chr1,Chr2,Chr3: AnsiChar): DWord;
begin
Result := DWORD(Chr0) + DWORD(Chr1) shl 8 + DWORD(Chr2) shl 16 + DWord(Chr3) shl 24;
end;
var
riff: record ckId, ckSize, fccType: DWord; end;
type
TChars = array[0..3] of AnsiChar; {用於類型轉換}
begin
Result := 'noneRIFF';
with TFileStream.Create(FilePath, fmOpenRead) do begin
Read(riff, SizeOf(riff));
Free;
end;
if (riff.ckId = mmioFOURCC('R', 'I', 'F', 'F')) then Result := TChars(riff.fccType);
end;
//測試:
begin
ShowMessage(GetRiffType('C:\WINDOWS\Media\Windows XP 啟動.wav')); {WAVE}
ShowMessage(GetRiffType('C:\Windows\clock.avi')); {AVI }
ShowMessage(GetRiffType('C:\Windows\notepad.exe')); {noneRIFF}
end;
關於 FOURCC_RIFF、mmioFOURCC、mmiOStringToFOURCC:
RIFF 格式的文件都是有若干 "塊" 來構成的, 每個塊都是有 4 個字符開頭(不足4個字符用空格補足);
這連續的 4 個字節剛好是一個 32 位整數的大小, 所以常常把它們當作一個整數讀出來判斷.
通過 MMSystem.mmiOStringToFOURCC 就可以獲取這樣的整數.
從 C/C++ 代碼中經常看到: mmioFOURCC; 它並非 winmm.dll 庫中的函數, 是在 C/C++ 中定義的宏.
這裡用 Delphi 模擬實現了這個函數. 其功能類似 mmiOStringToFOURCC.
MMSystem.FOURCC_RIFF 是個常量, 當需要 "RIFF" 對應的整數時直接用就是了. 舉例:
uses MMSystem;
{自定義的 mmioFOURCC 函數}
function mmioFOURCC(Chr0,Chr1,Chr2,Chr3: AnsiChar): DWord;
begin
Result := DWORD(Chr0) + DWORD(Chr1) shl 8 + DWORD(Chr2) shl 16 + DWord(Chr3) shl 24;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
f1,f2,f3,f4: FOURCC; {FOURCC = DWord;}
begin
f1 := mmiOStringToFOURCC('RIFF', 0);
f2 := mmiOStringToFOURCC('Riff', MMIO_TOUPPER); {第二個參數可以把字符串轉大寫}
f3 := mmioFOURCC('R', 'I', 'F', 'F');
f4 := FOURCC_RIFF;
ShowMessageFmt('%d, %d, %d, %d', [f1,f2,f3,f4]);
{1179011410, 1179011410, 1179011410, 1179011410}
end;