最稳方案是用 MediaInfo.Native 库读取音频时长,支持主流格式且不依赖系统组件;若 Duration 为空,则用 NAudio 的 TotalTime 推算真实时长。

用 MediaInfo 库读取音频时长最稳
Windows 自带的 Shell32 或 Windows.Media.Core 在非 UWP 环境下要么权限受限,要么依赖系统组件(比如需要安装 Media Feature Pack),而 MediaInfo 是纯托管封装,支持 MP3、FLAC、WAV、M4A 等主流格式,不依赖外部解码器。
实操建议:
- 通过 NuGet 安装
MediaInfo.Native(推荐)或MediaInfoLib,前者是官方维护的 .NET Standard 封装 - 不要直接调用原生 DLL,
MediaInfo.Native已处理好平台架构(x64/x86/ARM64)自动匹配 - 关键代码就三行:
var mi = new MediaInfo(); mi.Open(@"C:song.mp3"); var duration = mi.Get(StreamKind.General, 0, "Duration");,返回的是毫秒字符串,需long.TryParse转换 - 注意:
Duration字段可能为空——这不是 bug,而是某些 FLAC 或无头 WAV 文件本身没写入时长元数据,此时得靠解析音频帧推算(见下一条)
时长字段为空时,用 NAudio 解析音频帧算真实时长
MediaInfo 返回空 Duration 很常见,尤其当文件被剪辑过、或由某些录音软件生成。这时候不能硬等元数据,得“听”出来——打开音频流,读采样率和总样本数,自己算。
实操建议:
- 用
NAudio.Wave.WaveFileReader打开文件,它能自动识别格式并暴露WaveFormat.SampleRate和Length(单位是字节),再结合WaveFormat.BitsPerSample和声道数推导总样本数 - 更省事的做法是直接读
reader.TotalTime属性,它是TimeSpan类型,但注意:这个属性底层会触发一次完整扫描,首次访问较慢,别在循环里反复读 - 别用
WaveInEvent或WasapiLoopbackCapture去“播放式测量”,那是实时场景用的,这里纯属浪费 CPU - MP3 文件若含 ID3v2 标签且位置靠后,
WaveFileReader可能报Not a WAVE file错误——这不是格式问题,是它只认标准 RIFF WAV 头;此时应先用NAudio.Lame或TagLibSharp剥离标签,或换回MediaInfo
TagLibSharp 适合读 ID3/APE 标签,但别指望它返回准确时长
TagLibSharp 是 C# 里最成熟的标签库,对 MP3 的 ID3v2、FLAC 的 Vorbis Comments、M4A 的 iTunes atom 支持很好,但它设计目标是元数据(标题、艺术家、封面),不是媒体参数。
实操建议:
- 可以安全用来读
tag.Length,但这个值来自标签字段,不是实际解码结果——有些用户手动改过标签里的时长,或者导出时没更新,就会错 - 它不支持 WAV(无标准标签)、OGG(除非带 Vorbis Comment)、WMA(需额外编解码器),别硬套
- 如果只要封面图,用
tag.Pictures.FirstOrDefault()?.Data.ToArray()即可,别调tag.AlbumArt——后者在某些版本里有内存泄漏 - 多线程读同一文件时,
TagLib.File.Create不是线程安全的,要加锁或用using包裹单次操作
路径含中文或特殊字符时,所有库都要求传绝对路径
几乎所有音频元数据库在内部都会调用 Windows API 或 FFmpeg 的文件打开逻辑,相对路径 + 当前工作目录切换 + 中文路径组合起来,大概率触发 System.IO.FileNotFoundException 或静默失败(比如 MediaInfo 返回空字符串)。
实操建议:
- 一律用
Path.GetFullPath(@"./music测试.mp3")转成绝对路径再传给任何库 - 别信“我本地测试没问题”——发布到 IIS 或 Windows Service 后,当前工作目录通常是
C:WindowsSystem32,相对路径直接失效 -
file://URL 格式(如file:///C:/music/1.mp3)对MediaInfo和TagLibSharp都无效,它们只认文件系统路径 - 网络路径(
\serversharesong.mp3)可用,但需确保运行账号有共享+NTFS 权限,MediaInfo对 UNC 路径支持稳定,NAudio则可能抛NotSupportedException
真正麻烦的不是“怎么拿到时长”,而是同一份文件在不同库下返回不同结果——比如 MediaInfo 说 3:21.450,NAudio 算出来是 3:21.472,差 22 毫秒。这不是精度问题,是 MP3 的 Xing/VBRI 头、VBR 编码帧边界、以及是否计入 ID3v2 头长度导致的。生产环境得统一选一个库,并接受它的定义。










