Рекурсивный список файлов SD-карты
Я работаю над 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
@ewaca, 👍1
Обсуждение1 ответ
Лучший ответ:
Ошибку трудно заметить, но по существу она находится в исходной последовательности (не относящиеся к делу утверждения опущены):
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
я пытаюсь получить доступ к подкаталогам, но «это не работает». Исходный код с 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 busybeeitem.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