使用 LINQ 创建音乐播放列表 – 重制版





5.00/5 (3投票s)
对之前一篇文章的重写。仍然使用 LINQ,但在第二版中融入了更多内容。

介绍
我比较老派,仍然将我的 .mp3 音乐收藏按流派和艺术家组织在我的文件系统中。我知道,我知道,快去下载 iTunes 吧!我倒是可以,但那样我就无法享受编写自己的代码来自动为我构建播放列表的乐趣了。
当播放列表创建器完成 .m3u 文件的构建后,您可以通过双击来启动它们,使用 Windows Media Player 或您使用的任何媒体播放器/文件扩展名。
背景
在我写了关于如何使用简单的递归和 LINQ 轻松创建音乐播放列表的原始文章后,我回顾了我的工作并着手改进它。在这个版本中,我真正想“修复”的一个功能是能够在我的文件夹树的每个分支级别创建播放列表。你看,我的音乐收藏是按流派、然后按艺术家、然后按专辑组织的。所以我想能够启动播放列表,比如为“Rock”文件夹,它包含了我所有的摇滚音乐,并在树中的任何地方依此类推。
这部分代码的重要主题是认识到以这种方式创建播放列表将需要多次遍历文件系统——最终的叶子节点会一次又一次地被命中,直到它们本身被处理。Windows 在缓存磁盘活动方面做得非常出色,但我宁愿尝试编写一些高效的代码,而不必依赖另一个效率流程。
使用方法
再次强调,这段代码完成的主要工作是:
- 遍历文件系统,收集文件和文件夹的信息
- 将这些信息转储到一个内存中的类型化
DataSet
中 - 迭代
DataSet
内存以创建播放列表
DataSet
看起来是这样的:

几个简单的 DataTables
来存储收集到的磁盘信息。我仍然觉得类型化的 DataSets
对于这种快速存储数据任务很方便。它们易于设置,并且可以无缝地进行编码。
为了让我的代码结构更清晰,我有一个独立的程序集,它负责查找音乐文件以及构建播放列表。所有工作任务都在 PlaylistCreatorFP
项目中完成,该项目有一个名为 PCEngine
的主类,其中包含主要方法。
在这个重写过程中,我发现的一个有趣细节是 System.IO.Directory
类有一个 static
方法,可以查找给定路径下的所有目录。这并不是全新的信息,但我当时没有意识到还有一个参数可以传递,它会为你处理递归。
string[] dirs = Directory.GetDirectories
(inPath, PCConstants.ALLFILES_SEARCH_PATTERN, SearchOption.AllDirectories);
太棒了!我的磁盘遍历不再需要内存消耗巨大的手动递归了!
其余的代码相当易读(我希望如此;o),所以在此不详细说明了。PCEngine
类中的主要方法是 SearchDisk(...)
和 CreatePlayLists(...)
。其余的都是支持这些方法的方法,以及一个用于向主进程线程发送更新消息的 event
。
用户界面是另一回事。真是过度设计了 CodeProject 文章!UI 是一个小型 WPF 界面,允许用户输入一些关于从哪里开始搜索音乐文件、如何命名生成的播放列表文件等选项。只是为了让它成为一个更可用的程序而设计的简单功能。工作由一个 System.ComponentModel.BackgroundWorker
对象执行,以保持 UI 运行流畅。另外,还有一个主窗口的基类,它使用 Isolated Storage 来存储窗口在关闭时的位置和大小。
兴趣点
在编写过程中,我学到了:
System.IO.Directory.GetDirectories(...) static
方法的“内置”递归功能- 创建关系并使用
DataRelation
类及其ChildRelations(...)
方法以及.GetChildRows(...)
行方法来展平树形层次结构 - 如何创建
delegate
消息事件以方便地将消息传递回调用线程 - 如何在 WPF/XAML 中构建一个基类来扩展
Window
类
历史
- 2009 年 4 月 27 日:首次发布
我现在可能会暂时搁置这段代码。还有很多其他有趣的项目要去攻克!但如果你发现 bug 或有任何评论,请随时留言!