Как вы загружаете файл MP3, фактически не используя класс Content?

Я новичок в программировании на C Sharp и использую XNA SDK. Я пытаюсь сделать простую игру, чтобы помочь своим одноклассникам с подготовкой к школе, и я решил, что мне бы хотелось, чтобы у них был какой-то способ, чтобы они помещали музыку, которую они хотят слушать во время игры, в файл, и игра автоматически загрузит музыкальные файлы и воспроизведет их в списке воспроизведения.

До сих пор я могу заставить игру определять, являются ли файлы музыкой, определяя, содержит ли имя пути к файлу Contains(".mp3") , но я пытаюсь фактически загрузить имя файла в список типа Song, с помощью цикла for. Код выглядит так.

(Декларация)

List<Song> songsToPlay;
string[] fileNames

(Инициализировать)

fileNames[] = Directory.GetFiles(".\Music")

(Загрузить содержимое)

for (int i = 0; i < fileNames.Count(); i++)
{
      if (fileNames[i].Contains(".mp3")
      {
          songsToPlay.Add(fileNames[i]);
      }
}

Я пытался найти способ добавить целую папку в каталог содержимого и сделать что-то вроде

for (int i = 0; i < fileNames.Count(); i++)
{
    songsToPlay.Add(Content.Load<Song>("fileNames[i]") 
}

Я не смог найти способ сделать это... Кто-нибудь знает, как это сделать, или лучший способ сделать это?


person Matthew K. Crandall    schedule 07.01.2012    source источник


Ответы (2)


Если у вас есть файлы в содержимом вашего проекта, вы должны использовать класс ContentManager. Это дает вам больше, чем просто загрузка файлов. Например, вы можете использовать Content.Unload для выгрузки всех ваши данные, когда вы их больше не используете.

Нет необходимости избегать этого класса. На этой странице есть пример показывая, что именно вы пытаетесь сделать:

public static Dictionary<string, T> LoadContent<T>(
    this ContentManager contentManager, string contentFolder)
{
   var dir = new DirectoryInfo(contentManager.RootDirectory
       + "\\" + contentFolder);
   if (!dir.Exists)
      throw new DirectoryNotFoundException();

   var result = new Dictionary<string, T>();

   foreach (FileInfo file in dir.GetFiles("*.mp3"))
   {
      string key = Path.GetFileNameWithoutExtension(file.Name);

      result[key] = contentManager.Load<T>(
          contentManager.RootDirectory + "/" + contentFolder + "/" + key);
   }

   return result;
}

Вы можете использовать его следующим образом:

var songs = Content.LoadContent<Song>("Songs");

Небольшое улучшение этого кода...

Как только вы заработаете приведенный выше код, я также предлагаю вам внести небольшое изменение:

var dir = new DirectoryInfo(
    System.IO.Path.Combine(contentManager.RootDirectory, contentFolder));

Вы не должны вручную создавать пути с помощью конкатенации строк, если вы можете этого избежать. Я не знаю, можете ли вы сделать то же самое для ContentManager путей, поэтому вам, возможно, придется придерживаться конкатенации строк в этом случае.

Изменить: слишком много конструкций, которые вы еще не использовали в классе

Поскольку вы не использовали методы расширения или ключевое слово static в вашем классе и, вероятно, не использовали словари, вот более простой способ сделай это:

string contentFolder = "Music";
var dir = new DirectoryInfo(Content.RootDirectory + "\\" + contentFolder);

if (!dir.Exists)
{
    // Todo: Display a message to the user instead?
    throw new DirectoryNotFoundException();
}

string[] files = dir.GetFiles("*.mp3");

for (int i = 0; i < files.Count(); ++i)
{
    FileInfo file = files[i];
    string key = System.IO.Path.GetFileNameWithoutExtension(file.Name);

    var song = Content.Load<Song>(
        Content.RootDirectory + "/" + contentFolder + "/" + key);

    songsToPlay.Add(song);
}

Edit2: некоторое объяснение этого второго примера кода

Класс DirectoryInfo позволяет загружать каталог, чтобы может перечислить все файлы в нем.

Метод GetFiles в DirectoryInfo позволяет перечислять файлы с помощью сопоставления шаблонов в стиле подстановочных знаков. . Сопоставление шаблонов с подстановочными знаками для файлов означает, что при задании этих шаблонов:

  • *.* - вы ищете файлы с именем <anything>.<anything>
  • *.mp3 - вы ищете <anything>.mp3

throw означает создание исключения. Это преднамеренно остановит выполнение кода и отобразит правильное сообщение об ошибке («каталог не найден») и номер строки. Есть много информации об обработке исключений, так что я не буду пытаться отдать должное описанию.

GetFileNameWithoutExtension должен быть очевиден, потому что он хорошо назван .

Content.RootDirectory + "/" + contentFolder + "/" + key

Этот последний небольшой фрагмент кода создаст строку, содержащую корневой каталог контента, подкаталог ваших песен и имя каждого файла, используя имя, которое он может понять (поскольку он не знает о расширениях имен файлов).

var означает "любой тип, который я ему назначу". Это короткий путь. Например, вместо ввода:

List<string> someList = new List<string>();

Вы вводите:

var someList = new List<string>();

var должен знать, какой тип находится в правой части присваивания. Это полезно, потому что вы можете не повторяться.

Однако использование var не наделяет переменную магическими способностями. Вы не сможете назначить переменную другого типа после объявления переменной. Это просто сокращение для точно такой же функциональности.

person Merlyn Morgan-Graham    schedule 07.01.2012
comment
У меня есть небольшая проблема с этим... Я учусь программировать всего несколько месяцев... Я учусь в классе компьютерного программирования, и До сих пор мы никогда не говорили о том, как использовать статическое поле, и мы никогда не вдавались в подробности того, как использовать методы для возврата значения. Я пытался понять это, и у меня немного получилось, но я все еще потерян... Может быть, если бы был какой-то способ, я мог бы понять, как это на самом деле работает, немного глубже... - person Matthew K. Crandall; 08.01.2012
comment
@MatthewCrandall: это метод, а не поле. Хоть это и статично. Это также метод расширения. Я напишу модифицированную версию, которая соответствует вашим существующим учениям :) - person Merlyn Morgan-Graham; 08.01.2012
comment
Спасибо... Я всегда слышал это как статическое поле. Я знаю, что такое метод, но поскольку он был статическим, и я не понимаю, что на самом деле делает статический метод или что это такое, я просто назвал его статическим полем. Я просто никогда не работал с ContentManager, RootDirectory или Dictionary, поэтому я просто понятия не имею, что на самом деле происходит... может быть, если бы я мог получить больше объяснений того, как это работает, я мог бы действительно понять, что происходит :) - person Matthew K. Crandall; 08.01.2012
comment
@MatthewCrandall: Подойдет! Я разместил версию кода, которая теперь больше похожа на ваш исходный код. Постараюсь также добавить некоторые пояснения. - person Merlyn Morgan-Graham; 08.01.2012
comment
@MatthewCrandall: Хорошо, я добавил свои объяснения. Дайте мне знать, если я вас больше запутал, или если у вас есть вопросы, на которые я не ответил :) Кроме того, не стесняйтесь переходить по ссылкам extension methods или static, которые я указал в своем ответе, чтобы узнать о них немного больше. - person Merlyn Morgan-Graham; 08.01.2012
comment
На самом деле я следовал большей части этого, и я планирую кое-что прочитать по обоим из них... Я пытался добавить все это в метод LoadContent, но он возвращается с несколькими ошибками. Интересно, я что-то еще упускаю? Он говорит, что не может неявно преобразовать тип 'string' в 'System.IO.FileInfo' . У него та же ошибка позже, но в обратном порядке, когда он не может преобразовать из System.IO.FileInfo[] в string[]... две ошибки находятся в (соответственно) string[] files = dir.GetFiles(* мп3); и далее в FileInfo file = files[i]; - person Matthew K. Crandall; 08.01.2012
comment
Я только что просматривал код. dir.GetFile(*.mp3) Возвращает массив файлов типа System.IO.FileInfo[], а не в виде строки, поэтому также требуется некоторое преобразование из System.IO.FileInfo[] в строку[]. Я попытался настроить его, добавив .ToString() в конце инструкции, но затем он говорит, что не может преобразовать строку типа в строку типа [], поэтому мне интересно, нужно ли мне сохранить ее как строку, а затем использовать разделить, чтобы разбить строку на массив, а затем загрузить файл из этого массива строк, вместо того, чтобы пытаться дать значение типа string[] a DirectoryInfo[].... - person Matthew K. Crandall; 08.01.2012
comment
@MatthewCrandall: я, вероятно, испортил эту часть, потому что на самом деле я не писал код в компиляторе. FileInfo[] должно подойти для переменной files. - person Merlyn Morgan-Graham; 08.01.2012
comment
Ага. Я понял, что FileInfo будет работать сам по себе... нет проблем, это понятно. Теперь у меня другая проблема. Судя по всему, CSharp на самом деле не может напрямую загружать MP3, по крайней мере, так, как мы пытаемся заставить его работать. Постоянно пишет Ошибка, CSharp не может открыть файл. Вы уверены, что используете правильный загрузчик?... Есть ли способ проверить, есть ли MP3, преобразовать их в XNB. Обычно, когда я загружаю звук, я вручную добавляю его в Content References, и он автоматически преобразует его. Интересно, нужно ли мне программно конвертировать из MP3 в XNB, чтобы он работал. - person Matthew K. Crandall; 11.01.2012

Используйте метод Song.FromUri. :

Song.FromUri("audio name", new Uri(@"C:\audio.mp3"));

Путь к файлу не может содержать пробелы!

Обходной путь см. здесь: XNA 4 Song.fromUri, содержащий пробелы

person George Duckett    schedule 07.01.2012