开篇先交代一下背景, 因为本人喜欢在网上下载一些无损音乐放到本地听,时间一长,导致本地存放音乐的文件夹里的文件很多,看上去很杂乱,而一首一首歌去手动创建目录又很复杂,所以今天休息的时候闲来无事,想到是不是可以做一个小工具,根据音乐文件的歌手和专辑名去自动创建目录,把文件移动到创建好的目录。
说做就做,第一步,确定需求。这里其实很简单,就是我输入一个目录,这个工具就会把该目录下的音乐文件自动移动到对应的目录,目录规则为 根目录/歌手/专辑。确定了需求,接下来就是步骤:
- 遍历根目录下的所有文件;
- 筛选其中的音乐文件(有时下载的资源包括封面图);
- 找出音乐文件的歌手和专辑名,并拼装好新的目录;
- 将当前音乐移动到指定目录
下面放一下代码,因为本人用的是Windows系统,为了省事,这次就用了C#开发(主要是WinForm用着顺手),如果大家有更好的实现方式或者更棒的算法,欢迎提出~
目录结构(其实挺简单的,Logic层完全可以省略的)
界面(也很简单,不会做美工啥的,自己用的,实现功能为主吧)
按钮部分代码(这里没什么主要逻辑,还是调用MainLogic为主):
private void btnStart_Click(object sender, EventArgs e)
{
string rootPath = this.tbRootPath.Text.Trim();
MainLogic mainLogic = new MainLogic();
if (mainLogic.isPathExist(rootPath))
{
try
{
List<string> listFile = new List<string>();
DirectoryInfo directory = new DirectoryInfo(rootPath);
mainLogic.findFile(listFile, directory);
int num = 0;
foreach(string fileName in listFile)
{
if (mainLogic.isMusicFile(fileName))
{
string targetPath = rootPath;
string artist = mainLogic.getArtist(fileName);
string album = mainLogic.getAlbum(fileName);
if (!string.IsNullOrEmpty(artist) && !mainLogic.isAllQuestionMark(artist))
{
targetPath += "\\" + artist;
}
if (!string.IsNullOrEmpty(album) && !mainLogic.isAllQuestionMark(album))
{
targetPath += "\\" + album;
}
mainLogic.moveFile(fileName, targetPath);
num++;
}
}
showSuccessMessage("移动完成,本次处理文件" + num + "个");
}
catch (Exception ex)
{
showErrorMessage(ex.Message);
}
}
else
{
showErrorMessage("输入的路径不存在,请确认后操作");
}
}
遍历目录(这里还是使用递归,只记录文件,没有记录目录,代码部分引用自网友,感谢网友的无私分享~)
public void findFile(List<string> listFiles, DirectoryInfo directoryInfo)
{
FileInfo[] fileInfos = directoryInfo.GetFiles();
for (int i=0; i< fileInfos.Length; i++)
{
listFiles.Add(fileInfos[i].FullName);
}
DirectoryInfo[] directoryInfos = directoryInfo.GetDirectories();
for (int i=0; i < directoryInfos.Length; i++)
{
findFile(listFiles, directoryInfos[i]);
}
}
判断格式,因为有时会下载出封面等其他信息,我自己最后是只保留的音乐文件,所以这里没有管,如果大家有需求可以根据需要更改代码~
/// <summary>
/// 判断文件是否为音乐文件
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public bool isMusicFile(string fileName)
{
string extension = Path.GetExtension(fileName);
string targetExtension = ".mp3;.flac;.wma;.wav";
if (targetExtension.IndexOf(extension) != -1)
{
return true;
}
else
{
return false;
}
}
获取歌手和专辑信息(文件的其他信息也可以使用这个方法获取,可自行研究)
/// <summary>
/// 获取歌手名
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string getArtist(string fileName)
{
try
{
Shell32.Shell shell = new Shell();
Folder dir = shell.NameSpace(System.IO.Path.GetDirectoryName(fileName));
FolderItem item = dir.ParseName(System.IO.Path.GetFileName(fileName));
string artist = dir.GetDetailsOf(item, 20);
return artist;
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 获取专辑名
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string getAlbum(string fileName)
{
try
{
Shell32.Shell shell = new Shell();
Folder dir = shell.NameSpace(System.IO.Path.GetDirectoryName(fileName));
FolderItem item = dir.ParseName(System.IO.Path.GetFileName(fileName));
string album = dir.GetDetailsOf(item, 14);
return album;
}
catch (Exception ex)
{
throw ex;
}
}
移动文件:
/// <summary>
/// 移动文件
/// </summary>
/// <param name="sourcefileName"></param>
/// <param name="targetDir"></param>
public void moveFile(string sourcefileName, string targetDir)
{
try
{
if (!Directory.Exists(targetDir))
{
Directory.CreateDirectory(targetDir);
}
if (!File.Exists(sourcefileName))
{
throw new Exception("文件【" + sourcefileName + "】不存在,请检查");
}
int index = sourcefileName.LastIndexOf("\\");
string fileName = sourcefileName.Substring(index);
string targetDestination = targetDir + fileName;
if (!File.Exists(targetDestination))
{
File.Move(sourcefileName, targetDestination);
//File.Delete(sourcefileName);
}
}
catch (Exception ex)
{
throw ex;
}
}
后期发现一个问题,有些文件因为资源问题,专辑名和歌手都是问号,这里如果没有发现的话,就会造成有带问号的文件夹,还得自己处理,这里的办法是对这类文件不做处理,不拼接目录名,具体代码在上面界面的部分,下面为判断是否全部为问号的代码:
/// <summary>
/// 校验信息是否全为问号(有些歌曲文件会出现这种问题,可交由人工判断,或完成填写后使用)
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
public bool isAllQuestionMark(string info)
{
bool result = true;
for (int i=0; i<info.Length; i++)
{
if (info[i] != '?')
{
result = false;
break;
}
}
return result;
}
好了,至此就是这个小工具截至目前的主要代码,详细代码可以在这里看到:https://github.com/RazrZhang/MusicFilesHandler
小工具初版下载:
链接:https://pan.baidu.com/s/1T1pTYJn2JLaHmuLr1U-R8g
提取码:rr87
运行效果大概是下面的样子
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
写在最后:这个工具完成后比我预想的要简单一些,本来以为不同格式的文件要分开处理,但是后来发觉不需要,添加一个引用直接就完事了~这个工具运用System.IO这个库比较多,自己之前用这个类库用的也不是很多, 这次就当是做了一个练习吧,也想过用Java做,毕竟自己主攻方向是Java,但是自己GUI学的不咋地,而且又不如WinForm直接拖过来用就完事了,所以暂且就用C#吧,能达到目的就好,语言只是一种手段,不需要太多的纠结。当然这个工具也仅仅是实现了简单功能,能把大部分音乐进行比较好的分类,有些多歌手的,做的还不是很好,所以后期还会继续改进,有其他更好想法的朋友可以提出想法,我也会适当参考的~