Рекурсивный список файлов SD-карты

untagged

Я работаю над MP3-плеером и хочу получить список всех файлов на SD-карте.

Я нашел этот код в Интернете:

void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print('\t');
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print("...");
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem& fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

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

#define pushButton_pin   32
// Подключаем необходимые библиотеки
#include "Audio.h"
#include "SD.h"
#include "FS.h"
#include <Wire.h>
#include <TFT_eSPI.h> 
#include <SPI.h>

// подключения устройства чтения карт памяти microSD
#define SD_CS          5
#define SPI_MOSI      21 
#define SPI_MISO      19
#define SPI_SCK       18
 
// I2S-соединения
#define I2S_DOUT      22
#define I2S_BCLK      26
#define I2S_LRC       25
 
 // Создание аудиообъекта
Audio audio;

TFT_eSPI tft = TFT_eSPI();  
//digitalWrite(TFT_BL, 1);

int maxIndex;
uint32_t Freq = 0;
int Val;
String Btn, SongName;
String Status = "Idle";
bool state = true;
bool Current_State = state;
int Current_Millis;
int Previous_Millis;
int Debounce = 175;
int Xindex = 0;
int Yindex = 0;

const uint8_t maxFileNameSize = 50;
struct FileItem {
  bool isDir;
  char name[maxFileNameSize + 1];
  FileItem* upDir;
  std::vector<FileItem> elements;
};

File dir;
String CurrDir;
String NextDir;
String Song;
String Liste[50];


void setup() {
  pinMode(pushButton_pin, INPUT);
  setCpuFrequencyMhz(160);
  tft.init();
  tft.setRotation(3);
  tft.fillScreen(TFT_BLACK);
  tft.setTextWrap(false);
        
  // Устанавливаем карту microSD CS как ВЫХОД и устанавливаем ВЫСОКИЙ
  pinMode(SD_CS, OUTPUT);      
  digitalWrite(SD_CS, HIGH); 
    
  // Инициализируем шину SPI для карты microSD
  SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
    
  // Запускаем последовательный порт
  Serial.begin(115200);

  // Запускаем карту microSD
  if (!SD.begin(SD_CS))
  {
    Serial.println("Error accessing microSD card!");
    while(true); 
  }
  Serial.println("initialization done.");
  Serial.println("Creating structure of files");
  File root = SD.open("/");
  FileItem rootItem;
  if (strlen(root.name()) != 0)
    strncpy(rootItem.name, root.name(), maxFileNameSize);
  else
    strncpy(rootItem.name, "/", maxFileNameSize);
  rootItem.name[maxFileNameSize] = '\0';
  rootItem.isDir = true;
  readSdCard(root, rootItem);
  //Завершение листинга

  Serial.println ("----Disp----");
  displaySdCardContent(rootItem, 0);
}

void readSdCard(File dir, FileItem& parentItem) {
  while (true) {
    File entry = dir.openNextFile();
    if (!entry) {
      break;  // больше нет файлов
    }
    FileItem item;
    item.isDir = entry.isDirectory();
    strncpy(item.name,  entry.name(), maxFileNameSize); // https://cplusplus.com/reference/cstring/strncpy/
    item.name[maxFileNameSize] = '\0'; 
    parentItem.elements.push_back(item);
    Serial.printf("Add %s to %s\n", item.name, parentItem.name);
    if (entry.isDirectory()) {
      readSdCard(entry, item);
    }
  }
}

void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print("...");
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem& fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

Я попробовал это для доступа к каталогам второго уровня:

  FileItem* subFolder = &rootItem.elements.at(0);
  Serial.println ("----Disp----");
  FileItem _subFolder= *subFolder;
  
  displaySdCardContent(_subFolder, 0);

Но это не работает...

Вот что я получаю с последовательным монитором:

23:36:23.419 -> Add 11-Avalanche.mp3 to War Eternal
23:36:23.419 -> Add 12-Down To Nothing.mp3 to War Eternal
23:36:23.419 -> Add 13-Not Long For This World.mp3 to War Eternal
23:36:23.451 -> Add folder.jpg to War Eternal
23:36:23.451 -> Add Will To Power to Arch Enemy
23:36:23.483 -> Add 01-Set Flame To The Night.mp3 to Will To Power
23:36:23.483 -> Add 02-The Race.mp3 to Will To Power
23:36:23.515 -> Add 03-Blood In The Water.mp3 to Will To Power
23:36:23.515 -> Add 04-The World Is Yours.mp3 to Will To Power
23:36:23.515 -> Add 05-The Eagle Flies Alone.mp3 to Will To Power
23:36:23.547 -> Add 06-Reason To Believe.mp3 to Will To Power
23:36:23.547 -> Add 07-Murder Scene.mp3 to Will To Power
23:36:23.579 -> Add 08-First Day In Hell.mp3 to Will To Power
23:36:23.579 -> Add 09-Saturnine.mp3 to Will To Power
23:36:23.612 -> Add 10-Dreams Of Retribution.mp3 to Will To Power
23:36:23.643 -> Add 11-My Shadow And I.mp3 to Will To Power
23:36:23.643 -> Add 12-A Fight I Must Win.mp3 to Will To Power
23:36:23.675 -> Add folder.jpg to Will To Power
23:36:23.675 -> ----Disp----
23:36:23.675 -> Arch Enemy

Изменить: Элемент атрибутов, который я могу напечатать в displaySdCardContent()

14:58:54.763 -> ----Disp----
14:58:54.763 -> name : Arch Enemy
14:58:54.763 -> IsDir : 1

Отладка в ReadsdCard

⸮⸮item name : 07. [Through The Eyes Of A Raven].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :7
Add 07. [Through The Eyes Of A Raven].mp3 to CD1 - Khaos Legions
item name : 08. [Cruelty Without Beauty].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :8
Add 08. [Cruelty Without Beauty].mp3 to CD1 - Khaos Legions
item name : 09. [We Are A Godless Entity].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :9
Add 09. [We Are A Godless Entity].mp3 to CD1 - Khaos Legions
item name : 10. [Cult Of Chaos].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :10
Add 10. [Cult Of Chaos].mp3 to CD1 - Khaos Legions
item name : 11. [Thorns In My Flesh].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :11
Add 11. [Thorns In My Flesh].mp3 to CD1 - Khaos Legions
item name : 12. [Turn To Dust].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :12
Add 12. [Turn To Dust].mp3 to CD1 - Khaos Legions
item name : 13. [Vengeance Is Mine].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :13
Add 13. [Vengeance Is Mine].mp3 to CD1 - Khaos Legions
item name : 14. [Secrets].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :14
Add 14. [Secrets].mp3 to CD1 - Khaos Legions
item name : CD2 - Kovered In Khaos
item IsDir : 1
item size :0
parent item name : 2011 - Khaos Legions (2xCD, Ltd)
parent item IsDir : 1
Parent item size :2
Add CD2 - Kovered In Khaos to 2011 - Khaos Legions (2xCD, Ltd)
item name : 01. [Warning].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :1
Add 01. [Warning].mp3 to CD2 - Kovered In Khaos
item name : 02. [Wings Of Tomorrow].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :2
Add 02. [Wings Of Tomorrow].mp3 to CD2 - Kovered In Khaos
item name : 03. [The Oath].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :3
Add 03. [The Oath].mp3 to CD2 - Kovered In Khaos
item name : 04. [The Book Of Heavy Metal].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :4
Add 04. [The Book Of Heavy Metal].mp3 to CD2 - Kovered In Khaos
item name : Folder.jpg
item IsDir : 0
item size :0
parent item name : 2011 - Khaos Legions (2xCD, Ltd)
parent item IsDir : 1
Parent item size :3
Add Folder.jpg to 2011 - Khaos Legions (2xCD, Ltd)
item name : War Eternal
item IsDir : 1
item size :0
parent item name : Arch Enemy
parent item IsDir : 1
Parent item size :4
Add War Eternal to Arch Enemy
item name : 01-Tempore Nihil Sanat (Prelude in F minor).mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :1
Add 01-Tempore Nihil Sanat (Prelude in F minor).mp3 to War Eternal
item name : 02-Never Forgive, Never Forget.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :2
Add 02-Never Forgive, Never Forget.mp3 to War Eternal
item name : 03-War Eternal.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :3
Add 03-War Eternal.mp3 to War Eternal
item name : 04-As The Pages Burn.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :4
Add 04-As The Pages Burn.mp3 to War Eternal
item name : 05-No More Regrets.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :5
Add 05-No More Regrets.mp3 to War Eternal
item name : 06-You Will Know My Name.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :6
Add 06-You Will Know My Name.mp3 to War Eternal
item name : 07-Graveyard Of Dreams.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :7
Add 07-Graveyard Of Dreams.mp3 to War Eternal
item name : 08-Stolen Life.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :8
Add 08-Stolen Life.mp3 to War Eternal
item name : 09-Time Is Black.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :9
Add 09-Time Is Black.mp3 to War Eternal
item name : 10-On And On.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :10
Add 10-On And On.mp3 to War Eternal
item name : 11-Avalanche.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :11
Add 11-Avalanche.mp3 to War Eternal
item name : 12-Down To Nothing.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :12
Add 12-Down To Nothing.mp3 to War Eternal
item name : 13-Not Long For This World.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :13
Add 13-Not Long For This World.mp3 to War Eternal
item name : folder.jpg
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :14
Add folder.jpg to War Eternal
item name : Will To Power
item IsDir : 1
item size :0
parent item name : Arch Enemy
parent item IsDir : 1
Parent item size :5
Add Will To Power to Arch Enemy
item name : 01-Set Flame To The Night.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :1
Add 01-Set Flame To The Night.mp3 to Will To Power
item name : 02-The Race.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :2
Add 02-The Race.mp3 to Will To Power
item name : 03-Blood In The Water.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :3
Add 03-Blood In The Water.mp3 to Will To Power
item name : 04-The World Is Yours.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :4
Add 04-The World Is Yours.mp3 to Will To Power
item name : 05-The Eagle Flies Alone.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :5
Add 05-The Eagle Flies Alone.mp3 to Will To Power
item name : 06-Reason To Believe.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :6
Add 06-Reason To Believe.mp3 to Will To Power
item name : 07-Murder Scene.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :7
Add 07-Murder Scene.mp3 to Will To Power
item name : 08-First Day In Hell.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :8
Add 08-First Day In Hell.mp3 to Will To Power
item name : 09-Saturnine.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :9
Add 09-Saturnine.mp3 to Will To Power
item name : 10-Dreams Of Retribution.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :10
Add 10-Dreams Of Retribution.mp3 to Will To Power
item name : 11-My Shadow And I.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :11
Add 11-My Shadow And I.mp3 to Will To Power
item name : 12-A Fight I Must Win.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :12
Add 12-A Fight I Must Win.mp3 to Will To Power
item name : folder.jpg
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :13
Add folder.jpg to Will To Power
----end of listing ----
rootItem.element[0] name : Arch Enemy
rootItem.element[0] IsDir : 1
rootItem.element[0] size :0


, 👍1

Обсуждение

я пытаюсь получить доступ к подкаталогам, но «это не работает». Исходный код с displaySdCardContent(rootItem,0); отображать первый уровень, и мой тест также отображает только первый уровень, @ewaca

ОТ: Вы не устанавливаете значение upDir в своих элементах. Однако вы им не пользуетесь., @the busybee

На первый взгляд я не вижу очевидной ошибки, и у меня нет оборудования для воспроизведения. Пожалуйста, [отредактируйте] свой вопрос с результатами отладки вывода атрибутов item в displaySdCardContent(). Если это выглядит подозрительно, сделайте то же самое при построении дерева элементов в readSdCard()., @the busybee

вывод отладки уже есть в моем вопросе. Перед «23:36:23.675 -> ----Disp----» это выходные данные при построении дерева, а после — выходные данные displaySdCardContent()., @ewaca

Пожалуйста, прочитайте внимательно: я хотел бы видеть **все атрибуты** каждого элемента, переданные в displaySdCardContent()., @the busybee

Я могу получить доступ только к элементам в корне, и есть одна папка. Я могу просто напечатать name и isDir. «upDir» — это элемент, а «Элементы» — векторные элементы, я не могу его распечатать., @ewaca

Спасибо. Поскольку isDir равен 1, item.elements _должен_ повторяться. Судя по всему, это не так, поэтому напечатайте item.elements.size(). И так далее, вам нужно «пошагово» просмотреть данные с несколькими отпечатками., @the busybee

item.elements.size возвращает 0 ... o_O? 20:20:47.622 -> имя: Arch Enemy 20:20:47.622 -> IsDir: 1 20:20:47.622 -> размер:0, @ewaca

Следующий шаг логичен: добавьте отладочные отпечатки в readSdCard() для каждого завершенного item перед его добавлением и в setup() для rootItem.elements[0]., @the busybee

я отредактировал вопрос с помощью отладки readSdCard(). Я не знаю, почему я не могу получить начало, но я понимаю, что каждый элемент имеет размер, равный 0, но каждый раз, когда он добавляется в родительский каталог, размер родительского каталога увеличивается на 1, а когда он меняет каталог, родительский размер элемента перезапускается до 0., @ewaca

Спасибо за журнал отладки! Похоже, что readSdCard() работает так, как ожидалось, и заполняет ваше дерево. Должно быть что-то еще. К сожалению, мне сейчас нужно поспать, я вернусь через несколько часов., @the busybee

Мне кажется, я понимаю, что вы пытаетесь сделать; Похоже, вы строите древовидную структуру в стеке, рекурсивно перемещаясь по файловой структуре SD. Вы явно ожидаете, что древовидная структура останется неповрежденной после возврата окончательного вызова рекурсивно вызванной функции, чтобы вы могли затем перемещаться по этой древовидной структуре с помощью другой рекурсивной функции. Вы уверены, что дерево будет существовать в момент, когда вы пытаетесь по нему перемещаться?, @6v6gt

Тем временем у вас есть ответ, и, возможно, это решает проблему, но я создал быструю симуляцию Wokwi ESP32, включая образец файловой структуры, но с использованием LittleFS вместо файловой системы SD, чтобы с ней можно было экспериментировать в Интернете. Ядро похоже на ваше исходное простое рекурсивное сканирование, а не на ваше двухпроходное решение. Он основан на общем руководстве «randomnerd», и это, похоже, работает. https://wokwi.com/projects/383917656227391489, @6v6gt

спасибо, да, ответ решил мою проблему, но я сохраню ваш код на всякий случай ^^, @ewaca


1 ответ


Лучший ответ:

0

Ошибку трудно заметить, но по существу она находится в исходной последовательности (не относящиеся к делу утверждения опущены):

    FileItem item;
    // ...
    parentItem.elements.push_back(item);
    // ...
      readSdCard(entry, item);
    }

Метод push_back() копирует элемент в elements. Поскольку в этот момент item не имеет элементов, копия также не имеет их. Более поздние модификации item не меняют копию.

Есть несколько вариантов исправления.

1. Сначала выполните рекурсию, а затем нажмите:

    FileItem item;
    // ...
      readSdCard(entry, item);
    }
    // ...
    parentItem.elements.push_back(item);

Таким образом, вектор elements item собирает свои записи перед push_back().

Однако порядок отладочных сообщений меняется.

2. Рекурсия с копией:

    FileItem item;
    // ...
    parentItem.elements.push_back(item);
    // ...
      readSdCard(entry, parentItem.elements.back());
    }

В этом случае readSdCard() использует копию item в parentItem elements для сбора записи.

,

Большое спасибо !! кажется, это работает, я быстро попытался перемещаться по дереву и Serial.println(rootItem.elements[0].elements.at(1).elements[1].name); вернул mp3-файл! Теперь мне нужно разобраться с этим деревом, чтобы распечатать его на экране, но самое сложное уже сделано :) Еще раз спасибо!, @ewaca