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;
分类:
API WAVE 专栏
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
2008-11-06 WinAPI 字符及字符串函数(15): CharNext、CharPrev
2008-11-06 WinAPI 字符及字符串函数(14): CharToOem、OemToChar
2008-11-06 WinAPI 字符及字符串函数(13): lstrcmp、lstrcmpi - 对比串
2008-11-06 获取汉字编码的几种方法 - 回复"外来天客"的问题