SD получить путь к файлу.
- Войдите на сайт для отправки комментариев
Ср, 13/01/2016 - 13:20
Доброго времени суток!
Есть скетч использующий библиотеку SD
С помощью метода openNextFile() просмтариваю все содержимое карты (и вложенных папок) и найдя необходимый файл пытаюсь его удалить, но для SD.remove(); необходимо указывать полный путь а свойство file.name(); возвращает только имя файла. Как можно узнать полный путь к файлу?
Вот пример функции. Она должна удалить все вложенные файлы и папки начиная с заданной
Проблема тут в том, что dir.name() (стр. 11) возвращает текущую папку, а не полный путь к ней, соответственно папки и файлы второго уровня я не могу уже удалить
Так Вы сохраняйтё накопленный путь. Вы же начинаете с корня. Вот и заведите строку в которой сидит адрес корня. А когда заходите в папку, присоединяйте в хвост "\"<имя папкаи>. Зайдёте в подкпапку, опять присоединяйте. Так у Вас всегда под рукой будет полный путь к текущей папке.
Использовать глобальную переменную для хранения пути? А когда я начну возвращаться из рекурсивного дерева, мне этот путь обрезать с конца придется? Не очень красиво получается.
ЗЫ. Имею ввиду обсуждение приведенного кода из #1. Для задачи из ТК ваше решение вполне подходит.
Или предлагаете передавать полный путь в функцию отдельным параметром?
В файле SdFile.cpp есть функция, возможно это то что нужно:
/**
* Return a files directory entry
*
* \param[out] dir Location for return of the files directory entry.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t SdFile::dirEntry(dir_t* dir) {
// make sure fields on SD are correct
if (!sync()) return false;
// read entry
dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
if (!p) return false;
// copy to caller's struct
memcpy(dir, p, sizeof(dir_t));
return true;
}
Использовать глобальную переменную для хранения пути? А когда я начну возвращаться из рекурсивного дерева, мне этот путь обрезать с конца придется? Не очень красиво получается.
ЗЫ. Имею ввиду обсуждение приведенного кода из #1. Для задачи из ТК ваше решение вполне подходит.
Не, конечно же параметром. Например, типа String, причём передавать по значению. Т.е. при входе в функцию будет создаваться новый экземпляр. К нему присобачиваем "хвост", а при выходе и думать ни о чём не надо, т.к. оригинальный экземпляр не менялся.
В файле SdFile.cpp есть функция, возможно это то что нужно:
/**
* Return a files directory entry
*
* \param[out] dir Location for return of the files directory entry.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t SdFile::dirEntry(dir_t* dir) {
// make sure fields on SD are correct
if (!sync()) return false;
// read entry
dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
if (!p) return false;
// copy to caller's struct
memcpy(dir, p, sizeof(dir_t));
return true;
}
Я так понимаю, для возможности использования данной функции необходимо внести изменения в библиотеку SD. Я до этого еще не дорос.
В том же файле есть и SD.remove();
/**
* Remove a file.
*
* The directory entry and all data for the file are deleted.
*
* \param[in] dirFile The directory that contains the file.
* \param[in] fileName The name of the file to be removed.
*
* \note This function should not be used to delete the 8.3 version of a
* file that has a long name. For example if a file has the long name
* "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is a directory, is read only,
* \a dirFile is not a directory, \a fileName is not found
* or an I/O error occurred.
*/
uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) {
SdFile file;
if (!file.open(dirFile, fileName, O_WRITE)) return false;
return file.remove();
}
следовательно SD.dirEntry(dir_t* dir); должна вернуть директорию в переменной dir. Никаких изменений в библиотеку вносить не надо, все уже реализовано до нас, конечно если только мы говорим об одной и той же библиотеке.
Пробовал так:
Получаю в ответ: 'class SDClass' has no member named 'dirEntry'
Не видит компилятор такого метода у класса. Если не трудно, попробуйте пожалуйста у себя данный метод, стоит ли копать мне дальше в этом направлении?
Использовать глобальную переменную для хранения пути? А когда я начну возвращаться из рекурсивного дерева, мне этот путь обрезать с конца придется? Не очень красиво получается.
ЗЫ. Имею ввиду обсуждение приведенного кода из #1. Для задачи из ТК ваше решение вполне подходит.
Не, конечно же параметром. Например, типа String, причём передавать по значению. Т.е. при входе в функцию будет создаваться новый экземпляр. К нему присобачиваем "хвост", а при выходе и думать ни о чём не надо, т.к. оригинальный экземпляр не менялся.
Мне крайне не удобно было использовать String, поскольку потом все равно пришлось бы переводить в массив char, поэтому накидал такой код:
Стркутура папок/файлов на карте такова:
Request to reading SD card
TEMP/
1/
2/
ERROR.TXT 18268
2.TXT 18268
1.TXT 18268
Client disonnected
При выполнении кода получаю следующее:
Request to clear directory /
>
/TEMP
>
/TEMP/1
>
/TEMP/1/2
>
<
Remove folder /TEMP/1/2/ done
/TEMP/1/2/ERROR.TXT
Remove file /TEMP/1/2/ERROR.TXT error
<
Remove folder /TEMP/1/2/ERROR.TXT error
/TEMP/1/2/ERROR.TXT2.TXT
Remove file /TEMP/1/2/ERROR.TXT2.TXT error
/TEMP/1/2/ERROR.TXT2.TXT1.TXT
Remove file /TEMP/1/2/ERROR.TXT2.TXT1.TXT error
<
Remove folder /TEMP/1/2/ERROR.TXT2.TXT1.TXT error
<
Client disonnected
т.е. при выходе из функции в переменной path продолжает хранится информация о предыдущем пути к папке, хотя это вроде как другой экземпляр. Как такое получается?
Это если бы там был String, то был бы другой экземпляр. А так - нет, так надо ручками удалять то. что добавил.
При использовании String в SD.remove() SD.mkdir() у меня контроллер уходит в бесконечный ребут, а более старые версии IDE вообще не принимают такой тип данных в этих методах. Поэтому приходится конвертировать в *char. Поясните пожалуйста в чем принципиальное отличие String от *char? Они по разному хранятся в памяти? Почему для *char не создается отдельный экземпляр при рекурсивном вызове функции?
Так Вы ж указатель передаёте, кто ж за Вас будет экземпляры создавать? Убирайте хвост руками - ничего страшного. При входе запомните указатель на конечный нулевой символ, а при выходе вписывайте туда 0. Вот и всё убирание. Делов-то!
ок, спасибо!
Спасибо за информацию
Все таки решил через String, ибо так оказалось проще. Все работает, единственное непонятный для меня момент. Вот функция:
Обратите внимание что строки 16, 17 диблируют строки 11, 12, т.е. фактически после рекурсивного выхода из функции мне приходится по новой собирать полный путь. Если этого не делать, в переменной charPath помимо самого пути попадает всякий мусор, в частности в конце пути попадает символ '='. Откуда он там берется я так и не понял. Если не трудно, проясните пожалуйста этот момент.
rene, Вы всё слишком усложнили. Это не так делается. Зачем Вам вообще символьный массив, раз уж Вы взялись пользоваться String?
Я могу попытаться помочь Вам написать нормальный код, только у меня нет под рукой SD карты, чтобы всё проверить. Так что отлаживать придётся типа "я написал - Вы запустили". Согласны? Если да, то как писать, с char[] или со String?
Как я писал выше, метод SD.remove() не принимает тип String, по крайне мере у меня при попытке подсунуть в метод строку, устройство уходит в бесконечный ребут.
А так, да конечно согласен! Всегда интересно как выполняют ту же задачу профессионалы, если вас не затруднит, покажите как делать с char
Хорошо, завтра я сделаю с char[].
Ну, попробуйте вот так.
Как видите, техника работы с массивом простая. В начале я запоминаю где находится терминальный 0, а в конце восстанавливаю его на место. Так что, что бы мы ни делали внутри, при нормальном (без ошибки) выходе иуффер всегда в точности восстанавливается. При выходе по ошибке я умышленно не восстанавливаю его, чтобы там сохранилось имя проблемного файла и т.п. (см. комментарий перед функцией).
Только, я уже предупреждал, сам я не запускал (нет у меня сейчас картридера), так что гарантировать, что заработает - не могу. Если будут проблемы, опишите подробно в чём выражаются. Я тогда. может быть отладочных печатей понаставлю - отладим. в общем, куда она денется.
Там я что-то прокомментировал, но если остались непонятки, спрашивайте.
Да, кстати. По уму бы в строках 27 и 37 надо вместо uint8_t писать CLEAR_FOLDER_RESULTS. Так более грамотно, но .... спасибо разработчикам IDE за то, что в текст грязными руками лезут. Кто-то здесь писал, что в новом IDE такого уже нет и там можно писать правильно, но я пока того нового IDE не пробовал.
Все работает, огромное человеческое спасибо! Буду изучать и применять полученный опыт.
Да, незачто. Я удивлён. что с первого тычка заработало. Но если чего потом вылезет, пишите.