我正在编写一个小应用程序来修改音频文件的 ID3-Tags。UI 非常简单:您选择您的媒体库,并可以递归地将各种代码逻辑应用于所有文件。
我正在使用 TagLib 在我的项目中读取和写入标签。
为了使用图书馆,我需要阅读所有标签并将它们存储在专辑列表中。
问题:在函数private void GenerateClassifiedLibrary(List files)中抛出了InvalidOperationException,我找不到任何原因,为什么会发生这种情况。
这是主应用程序的源代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
namespace Music_Metadata_Experiments
{
public partial class Form1 : Form
{
// Global Variables Declaration
public static List<Album> classifiedLibrary = new List<Album>();
// classifiedLibrary is a List of Albums
// Albums contain Songs
// Songs contain Tags like "TITLE", "ARTIST", "ALBUM", "GENRE", etc. which can be read and displayed by every Media Player.
// Start up
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
txtLibraryPath.Text = Environment.GetEnvironmentVariable("USERPROFILE") + "\\Music";
}
private void BtnSelectLibrary_Click(object sender, EventArgs e)
{
String libraryPath = "";
List<String> musicFiles;
if (libraryBrowserDialog.ShowDialog() == DialogResult.OK)
{
libraryPath = libraryBrowserDialog.SelectedPath;
}
if (libraryPath != null && libraryPath != "")
{
txtLibraryPath.Text = libraryPath;
Log("New Library: " + libraryPath);
}
MessageBox.Show("Mediathek wird eingelesen. Dieser Vorgang kann je nach Größe sehr lange dauern.\nDrücke Strg+Shift+Esc für mehr technische Infos.\n\nBitte warten!");
// Reading the Library:
musicFiles = GetFilesFromLibrary(libraryPath);
GenerateClassifiedLibrary(musicFiles);
}
// Adjustable Code
private void ExecuteLogic1_Click(object sender, EventArgs e)
{ // Not implemented yet
// Goal: Fix this problem -> Song 1 from DISKNUMBER 1 and Song 1 from DISKNUMBER 2 are shown underneath each other, because DISKNUMBER is missing or corrupted.
// Function: Finds multiple Songs having TITLENUMBER == 1 but are in the same ALBUM and have the same DISKNUMBER or no DISKNUMBER
Log("Executing Logic 1");
Log("Library Count: " + classifiedLibrary.Count);
foreach (Album album in classifiedLibrary)
{
Log("Album: " + album.Name);
}
}
private void ExecuteLogic2_Click(object sender, EventArgs e)
{
}
private void ExecuteLogic3_Click(object sender, EventArgs e)
{
}
private void ExecuteLogic4_Click(object sender, EventArgs e)
{
}
private void ExecuteLogic5_Click(object sender, EventArgs e)
{
}
private void ExecuteLogic6_Click(object sender, EventArgs e)
{
}
private void ExecuteLogic7_Click(object sender, EventArgs e)
{
}
private void ExecuteLogic8_Click(object sender, EventArgs e)
{
}
// Helper Methods
private List<String> GetFilesFromLibrary(string libraryPath)
{
String currentFileName = null;
String fileExtensionToScanFor = "mp3";
bool skipOnError = true;
List<String> files = new List<String>();
try
{
foreach (string file in Directory.EnumerateFiles(libraryPath, "*." + fileExtensionToScanFor, SearchOption.AllDirectories))
{
currentFileName = file;
files.Add(file);
}
Log("Found " + files.Count + " Files in Library");
}
catch (Exception any)
{
Console.WriteLine("Erroar reading file: " + currentFileName + " // Problem: " + any.Message);
if (skipOnError == false)
{
Application.Exit();
}
}
return files;
}
private void GenerateClassifiedLibrary(List<String> files)
{
Log("Generating a Library to work with");
TagLib.File currentFile = null;
foreach (string song in files) // ALL Songs found in Library Folder
{
try
{
currentFile = TagLib.File.Create(song);
String trackAlbum = currentFile.Tag.Album;
// Add at least 1 Album to classifiedLibrary
if (classifiedLibrary.Count < 1)
{
List<TagLib.File> albumTrackList = new List<TagLib.File>();
albumTrackList.Add(currentFile);
Album firstAlbum = new Album(trackAlbum, albumTrackList);
classifiedLibrary.Add(firstAlbum);
}
// Find an Album in classifiedLibrary to which this track belongs to
foreach (Album album in classifiedLibrary) // FIXME: InvalidOperationException thrown HERE
{
Console.WriteLine("Album: " + album.Name);
Console.WriteLine("Track: " + currentFile.Tag.Title); // not matching to album above
if (album.Name == trackAlbum)
{
// Album found in classifiedLibrary
Log("EXISTING Album: " + trackAlbum + " | Track Count = " + album.Tracks.Count);
// Now checking if the track exists or add it
List<TagLib.File> tracks = album.Tracks;
foreach (TagLib.File track in tracks)
{
if (track == currentFile)
{
// Already added to this Album!
Log("Already added: " + track.Tag.Title);
}
else
{
if (track.Tag.Album == currentFile.Tag.Album)
{
tracks.Add(track);
Log("X Added Track '" + track.Tag.Title + "' to '" + album.Name + "'.");
}
else
{
// Next one.
}
// Next one.
}
// Next one.
}
album.Tracks = tracks;
}
else
{
// Album not found in classifiedLibrary - FIXME: Album existiert und wird trotzdem neu erstellt
Log("NEW Album: " + trackAlbum);
List<TagLib.File> trackOrigin = new List<TagLib.File>();
Album newAlbum = new Album(trackAlbum, trackOrigin);
newAlbum.Tracks.Add(currentFile);
Log("Y Added Track '" + currentFile.Tag.Title + "' to '" + newAlbum.Name + "'.");
classifiedLibrary.Add(newAlbum);
Console.WriteLine("SUCCESS 1");
}
Console.WriteLine("SUCCESS 2");
} // ------------------------------ Exception
Console.WriteLine("SUCCESS 3");
}
catch (Exception any)
{
Console.WriteLine("------------------------------------------");
Console.WriteLine("GenerateClassifiedLibrary: A more fatal Erroar reading file: " + currentFile.Name);
Console.WriteLine("Exception: " + any.ToString());
Console.WriteLine("------------------------------------------");
}
}
// Generating classifiedLibrary done.
Log("Generated Library Contents: " + classifiedLibrary.Count + " Albums in classifiedLibrary");
}
private void Log(String line)
{
RtbLogs.Text += "\n" + line;
}
}
}
这里是Album对象的来源:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Music_Metadata_Experiments
{
public class Album
{
public String Name
{
get; set;
}
public List<TagLib.File> Tracks
{
get; set;
}
public Album(String name, List<TagLib.File> tracks)
{
Name = name;
Tracks = tracks;
}
public bool Contains(String trackTitle)
{
try
{
foreach (TagLib.File track in Tracks)
{
if (track.Tag.Title == trackTitle)
{
return true;
}
else
{
return false;
}
}
}
catch (Exception e)
{
Console.WriteLine("------------------------------------------");
Console.WriteLine("Exception occured while checking Album.Contains(" + trackTitle + ")");
Console.WriteLine(e.Message);
Console.WriteLine("------------------------------------------");
return false;
}
return false;
}
}
}
控制台输出示例:
Album: Holz (Weihnachtslied) - Single
Track: Curse My Name
SUCCESS 1
SUCCESS 2
Ausnahme ausgelöst: "System.InvalidOperationException" in mscorlib.dll
------------------------------------------
GenerateClassifiedLibrary: A more fatal Erroar reading file: C:\Users\XXX\Music\iTunes\iTunes Media\Music\Blind Guardian\At the Edge of Time\1-05 Curse My Name.mp3
Exception: System.InvalidOperationException: Die Sammlung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden.
bei System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
bei System.Collections.Generic.List`1.Enumerator.MoveNextRare()
bei System.Collections.Generic.List`1.Enumerator.MoveNext()
bei Music_Metadata_Experiments.Form1.GenerateClassifiedLibrary(List`1 files) in C:\Users\XXX\Documents\Projekte\Music Metadata Experiments\Music Metadata Experiments\Form1.cs:Zeile 152.
------------------------------------------
顺便说一句:我是 C# 新手
--
编辑:它现在按预期工作。我还将应用程序设置为 x64 以启用大型音乐库的处理。
更新项目:https ://1drv.ms/u/s!AphAKlhyqhP4g2eEk-3aqLeifo89?e=ACkb6w