Получение даты и времени создания файла SD.h
- Войдите на сайт для отправки комментариев
Сб, 27/08/2022 - 18:25
Всем доброго времени. Подскажите пожалуйста как получить дату и время создания файла?
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
File file;
unsigned long prev = 0;
tmElements_t tm;
void dateTime(uint16_t* date, uint16_t* time)
{
*date = FAT_DATE(tmYearToCalendar(tm.Year), tm.Month, tm.Day);
*time = FAT_TIME(tm.Hour, tm.Minute, tm.Second);
}
// Файл создан из примера
Serial.begin(9600);
SdFile::dateTimeCallback(dateTime);
if (!SD.begin(10))
{
Serial.println("SD.begin failed");
while (1);
}
file = SD.open("TEST_IT.TXT", FILE_WRITE);
file.println("Good write!");
file.close();
Serial.println("Done");
Вот только ума ни приложу - чем прочитать атрибуты файла, в числе которых особенно интересует время создания, изменения файла. 4 часа поиска в интернете не привели к результату.
Ты явно хочешь странного. Как ардуина сможет получить доступ к файловой системе компа?
Благодарю за внимание. Видимо я недостаточно раскрыл суть вопроса, меня интересует не ПК, а SD карта на которую ардуина сама же и пишет и читает, вопрос - как узнать, когда она это записала, прочитала или изменила.
Кто вам мешает писать лог с датой и временем в ещё один файл на ту же SD
Благодарю за предложение. Вижу необходимость дополнить свой вопрос - требуется решение без "обходных путей", в том числе писать в файл дату его создания. Основанием является использование созданных файлов для анализа во внешней программе.
https://arduino.ru/forum/programmirovanie/izmenenie-failovykh-atributov-daty-vremeni-pri-sozdaniikorrektirovke-failov-n
А чем не угодили штатные средства самой библиотеки SD? С ними что-то не так?
У структуры directoryEntry есть целая куча полей для даты и времени создания, последней модификации и последнего доступа. Вот они:
Читаете каталог и для каждого файла имеете всю информацию.
Или я чего- то недопонял?
Премного благодарен! Это как раз то что я и искал, только вот структуру эту для отдельного файла... Ещё раз спасибо! Пошёл искать описание по структуре как её правильно прочесть.
У класса SdFile есть метод dirEntry. Вот он эту структуру и читает.
https://arduino.ru/forum/programmirovanie/izmenenie-failovykh-atributov-daty-vremeni-pri-sozdaniikorrektirovke-failov-n
ТС, ты туда заходил вообще??? Там все с примерами!...
ТС, ты туда заходил вообще??? Там все с примерами!...
Там установка, а не чтение, а это две большие разницы.
А с чтением там не так просто. Метод, о котором я говорил, относится к SdFile , а SdFile член в классе File - private, до него не так легко добраться.
Можно плюнуть и перенести его в public, а можно (если не хочется трогать системную библиотеку и помнить об этом всякий раз, когда IDE обновляешь) просто не пользоваться верхним уровнем (классом File) а всё делать на честном SdFile. Вот, например, печать имён файлов и их дат/времени создания из корневого каталога. Подкаталоги делать не стал, чтобы ТС мозг не выносить рекурсией.
#include <SPI.h> #include <SD.h> const uint8_t pinCS = 4; // // Печать даты и времени создания файла из элемента каталога de // void printDateTime(const dir_t & de) { // ДД.ММ.ГГГГ ЧЧ:ММ:СС // 12345678901234567890 char buffer[20]; sprintf(buffer, "%02d.%02d.%04d %02d:%02d:%02d", FAT_DAY(de.creationDate), FAT_MONTH(de.creationDate), FAT_YEAR(de.creationDate), FAT_HOUR(de.creationTime), FAT_MINUTE(de.creationTime), FAT_SECOND(de.creationTime)); Serial.println(buffer); } // // Печать имени файла из элемента каталога de // в хвост добавляются пробелы до ширины 14 // void printName(const dir_t & de) { int8_t w = 0; for (uint8_t i = 0; i < 11; i++) { if (de.name[i] == ' ') continue; if (i == 8) { Serial.print('.'); w++; } Serial.write(de.name[i]); w++; } if (DIR_IS_SUBDIR(&de)) { Serial.print('/'); w++; } for (; w < 14; w++) Serial.print(' '); } // // // void setup(void) { Serial.begin(9600); // // Подключаемся к карте Sd2Card card; if (!card.init(SPI_HALF_SPEED, pinCS)) { Serial.println("Initialization failed. Check wirings!"); return; } else { Serial.println("Card is ready!"); } // // Открываем файловую систему SdVolume volume; if (!volume.init(card)) { Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); return; } else { Serial.println("File system is okay!"); } // // Открываем корневой каталог SdFile root; root.openRoot(volume); // // Печатаем корневой каталог (имена и даты файлов) dir_t p; while (root.readDir(& p)) { if (p.name[0] == DIR_NAME_FREE) break; // Пропустить удалённые фалы и "." с ".." if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue; // Печатаем только файлы и названия директорий if (!DIR_IS_FILE_OR_SUBDIR(& p)) continue; printName(p); // Печатаем имя файла printDateTime(p); // Печатаем дату и время } root.close(); } void loop(void) {}Результат:
Огромнейшее спасибо! Ваш код заработал фактически сразу (только пин SS поменял в соответствии со своим подключением)
Благодаря Вам, Евгений, вопрос в целом решён.
Есть только один момент, но возможно это уже в аппаратной части, или же нет... А именно - есть две разные sd-card, обе в FAT32, но на одной код с использованием SdFat работает, а на другой нет. При этом в коде без использования SdFat ситуация обратная.
Конкретно:
PS: Сейчас я конечно же пока буду работать с той картой которая работает с вашим кодом. Тем не менее, всё таки на долгие зимние вечера, может есть какие нибудь предложения, или возможно уже сталкивались с подобной ситуацией и есть решение?
Скорости SPI_HALF_SPEED, SPI_QUARTER_SPEE менял, но как и предполагал - результат 0;
Евгений Петрович, там в #1 «официальный пример»:
void printTimestamps(SdFile& f) { dir_t d; if (!f.dirEntry(&d)) error("f.dirEntry failed"); cout << pstr("Creation: "); f.printFatDate(d.creationDate); // и тд }Но уже не суть...
По картам:
Евгений Петрович, там в #1 «официальный пример»:
Это да. Там в поставке даже есть пример listfiles - который всю директорию печатает, но ни в этом примере, ни в том, до дат ручками не добираются, вся спрятано.
Ну, в таких случаях надо смотреть в чём разница. Если Вы откроете исходник, Вы увидите, что метод begin не содержит никакого волшебства, он вызывает тот же init и, заодно, открыват том и корневой каталог (т.е. то же самое, что в противном случае Вы делаете руками). Вот он:
boolean SDClass::begin(uint8_t csPin) { if (root.isOpen()) { root.close(); } /* Performs the initialisation required by the sdfatlib library. Return true if initialization succeeds, false otherwise. */ return card.init(SPI_HALF_SPEED, csPin) && volume.init(card) && root.openRoot(volume); }Как видите, если begin ломается, значит ломается что-то из трёх: card.init, volume.init или root.openRoot.
Поставьте ту карту, на которой ломается begin и попробуйте эти три метода вызвать руками с проверкой, чтобы увидеть кто из них ломается. Тогда уже можно будет смотреть почему он ломается.
Собственно, так всегда и разбираются.
И ещё, пожалуйста, вставляйте код правильно.