将 Windows Media Player 音乐元数据导出到 XML 文件






3.50/5 (3投票s)
一个 C# 应用程序,使用 Windows Media Player API 将所有音频元数据导出到 XML 文件
引言
本文介绍如何将 Windows Media Player 中的数据导出到 XML 文件,并简要介绍 COM Interop 以及 C# 3.0 中的一些新功能,即:对象初始值设定项、自动实现的属性和 LINQ to XML;它绝不是对这些功能的全面介绍,但希望能让您了解它们。
背景
在浏览我旧的 .NET 1.1 应用程序时,我发现一个应用程序仍然被我的每周备份脚本使用,但我已经很久没有投入时间了。它的目的是将 Windows Media Player 中的音频条目列表导出到 CSV(逗号分隔值)文件中,然后可以将其加载到 Excel 中。
在本文中,我将创建一个更新的版本,并研究如何优化代码以利用更新的框架功能,合理化类并修复现有实现中发现的问题。
Using the Code
COM 互操作
对我来说,COM 就像一个烦人的阿姨,你在聚会上坐在她旁边,却无法摆脱;你不得不怀疑,经过这么多年的 .NET,为什么一切都没有一个托管库......但我在跑题了。

创建对 Windows Media Player COM 库的引用需要打开“引用”对话框,选择“COM”选项卡,然后向下滚动到“Windows Media Player”,在我的机器上有两个条目,您需要路径类似于 "c:\windows\system32\wmp.dll" 的那个。 应该为“WMPLib”添加一个引用,并将一个互操作文件“Interop.WMPLib.dll”放在 bin 文件夹中;然后只需添加 WMPLib
命名空间。MediaPlayer
包装类的基本结构如下
...
using WMPLib;
class MediaPlayer : IDisposable
{
private WindowsMediaPlayer mp;
private IWMPMediaCollection media;
private int titleIndex;
...
public MediaPlayer()
{
this.mp = new WindowsMediaPlayer();
this.media = mp.mediaCollection;
// store the index of each property to improve performance
this.titleIndex = media.getMediaAtom("Title");
...
}
public void Dispose()
{
if (mp != null)
{
mp.close();
}
}
}
由于我们正在使用 COM,因此至关重要的是我们在之后进行清理,否则可能会/将会/可能(删除适用项)发生内存泄漏。IDisposable
接口的简单实现意味着我们不必担心 何时 会发生清理,而只需担心垃圾回收会释放所有使用的资源。
检索数据
接下来,我获取所有“音频”类型媒体的集合,使用 get_Item(i)
方法迭代项目,并将它们添加到我们的 MusicEntry
列表中(该列表被初始化为与集合相同的大小,以便预先分配内存空间)。通过 mediaItem.getItemInfoByAtom
检索每个属性。
public List<MusicEntry> GetMusicLibrary()
{
List<MusicEntry> entries;
IWMPPlaylist mediaList = null;
IWMPMedia mediaItem;
try
{
// get the full audio media list
mediaList = media.getByAttribute("MediaType", "Audio");
entries = new List<MusicEntry>(mediaList.count);
for (int i = 0; i < mediaList.count; i++)
{
mediaItem = mediaList.get_Item(i);
// create the new entry and populate its properties
entry = new MusicEntry()
{
Title = GetTitle(mediaItem),
Album = GetAlbum(mediaItem),
Artist = GetArtist(mediaItem),
TrackNumber = GetTrackNumber(mediaItem),
Rating = GetRating(mediaItem),
FileType = GetFileType(mediaItem)
};
entries.Add(entry);
}
}
finally
{
// make sure we clean up as this is COM
if (mediaList != null)
{
mediaList.clear();
}
}
return entries;
}
...
private string GetAlbum(IWMPMedia mediaItem)
{
return mediaItem.getItemInfoByAtom(albumIndex);
}
请注意在 MusicEntry
类的实例创建时使用了 C# 3.0 对象初始值设定项。我还将 MusicEntry
类的属性转换为自动实现。
// public property backed by a private field
private string _artist;
public string Artist
{
get { return _artist; }
set { _artist = value; }
}
// auto-implemented property
public string Artist { get; set; }
为什么 XML 优于 CSV
最初,我使用 CSV 文件,因为 Excel 可以很好地读取它,这意味着我不必使用 Excel Interop(或 Visual Studio Tools for Office),但在重构代码时,我发现 Excel 无法读取 CSV 文件中的 Unicode 字符,即使其他文件类型可以正确读取,你也会得到 "é" 代替 "é" (叹气)。
切换到 XML 允许字符被正确读入 Excel,并且使用 LINQ to XML 简化了代码:
- 删除
entries.Sort
方法调用和 Lambda 表达式 - 删除
MusicEntry.CompareTo
方法 - 删除文件处理命名空间和逻辑
- 不再需要在 CSV 字符串中转义双引号
- 不再需要执行行级字符串操作和连接
LINQ to XML 语法比定制的 CSV 编写器和(现在过时的)XmlDocument
都更优雅,它还提供排序、自动转义保留字符和文件处理(以及其他非常多的功能)。
public static void MusicListToXml(string outputPath, List<musicentry> entries)
{
XElement x = new XElement("Music",
from entry in entries
orderby entry.Artist, entry.Album, entry.TrackNumber
select new XElement("Entry",
new XAttribute("Artist", entry.Artist),
new XAttribute("Album", entry.Album),
new XAttribute("Title", entry.Title),
new XAttribute("Track", entry.TrackNumber.ToString()),
new XAttribute("Rating", entry.Rating.ToString()),
new XAttribute("FileType", entry.FileType)));
x.Save(outputPath);
}
XML 输出是紧凑的,形式如下
<Music>
<Entry Artist="Zero 7" Album="When It Falls" Title="Warm Sound"
Track="1" Rating="" FileType="wma" />
...
</Music>
要将 XML 文件加载到 Excel 2003 中,我选择了“以只读工作簿形式”打开 XML 选项,它以合理的格式显示数据

结论
时代在变,文件格式也在变,虽然 CSV 文件方法在 .NET 1.1 中快速而简单,但 Excel 中的 Unicode 显示问题是一个将转换为 XML 的充分理由,并且通过 LINQ 的强大功能,数据操作变得轻而易举。此外,通过使用对象初始值设定项、自动实现的属性和泛型,此导出器得到了简化,并且变得更加健壮 - 在我看来是双赢的。
历史
- 版本 1.0 - 初始发布