#include "FileLib.h" FileLibClass::FileLibClass(StorageType type) : _type(type) {} FileLibClass::~FileLibClass() { _printMessage("Unmounting file system\n"); if (_type == StorageType::FL_SPIFFS) { LITTLEFS.end(); } else if (_type == StorageType::FL_MMC) { SD_MMC.end(); } else if (_type == StorageType::FL_SD) { SD.end(); } } bool FileLibClass::begin(uint8_t csPin, uint8_t misoPin, uint8_t mosiPin, uint8_t sckPin) { _printMessage("Initializing file system\n"); if (_type == StorageType::FL_SPIFFS) { _filesystem = &LITTLEFS; return LITTLEFS.begin(true); } if (_type == StorageType::FL_MMC) { _filesystem = &SD_MMC; return SD_MMC.begin(); } if (_type == StorageType::FL_SD) { _spi.begin(sckPin, misoPin, mosiPin, csPin); _filesystem = &SD; return SD.begin(5, _spi); } return false; } File FileLibClass::openForWriting(const char *fileName) { _printMessage("Opening file '%s' for writing\n", fileName); return _filesystem->open(fileName, FILE_WRITE); } File FileLibClass::open(const char *fileName, const char *mode) { if (!_filesystem) { _printMessage("File system not initialized"); return File(); // Return an empty File object if filesystem is not initialized } return _filesystem->open(fileName, mode); } bool FileLibClass::readPartial(const char *fileName, uint32_t startPos, uint8_t *buffer, uint16_t bufferSize) { if (!_filesystem) { _printMessage("File system not initialized"); return false; } File file = _filesystem->open(fileName, FILE_READ); if (!file) { _printMessage("Failed to open file"); return false; } if (!file.seek(startPos)) { _printMessage("Failed to seek to position %u in file", startPos); file.close(); return false; } size_t bytesRead = file.read(buffer, bufferSize); file.close(); if (bytesRead == 0) { _printMessage("No data read from file"); return false; } return true; } bool FileLibClass::write(const char *fileName, const uint8_t *data, size_t dataSize, bool append) { _printMessage("Writing %d bytes to file '%s'\n", dataSize, fileName); File file = _filesystem->open(fileName, append ? FILE_APPEND : FILE_WRITE); // Sanity check if (!file || file.isDirectory()) { _printMessage("Failed to open file '%s' for writing\n", fileName); return false; } // size_t written = file.write(reinterpret_cast(data), dataSize); size_t written = 0; for (size_t i = 0; i < dataSize; i++) { written += file.write(data[i]); } // Confirm that the data was written if (written == dataSize) { file.close(); return true; } if (written > 0) { _printMessage("Only wrote %d bytes of %d\n", written, dataSize); file.close(); return false; } _printMessage("Failed to write to file '%s'\n", fileName); file.close(); return false; } bool FileLibClass::writeString(const char *fileName, const uint8_t *data, bool append) { _printMessage("Writing string to file '%s'\n", fileName); // use strlen so we don't write the null terminator int strLen = strlen((char *)&data); return write(fileName, reinterpret_cast(data), strLen, append); } void FileLibClass::listDir(const char *dirName, uint8_t levels) { if (!_verbose) { return; } _printMessage("Listing directory: %s\r\n", dirName); File root = _filesystem->open(dirName); if (!root) { _printMessage("− failed to open directory"); return; } if (!root.isDirectory()) { _printMessage(" − not a directory"); return; } File file = root.openNextFile(); while (file) { if (file.isDirectory()) { Serial.printf(" DIR : %s\n", file.name()); if (levels) { listDir(file.name(), levels - 1); } } else { Serial.printf(" FILE: %s", file.name()); Serial.printf("\tSIZE: %d\n", file.size()); } file = root.openNextFile(); } } bool FileLibClass::read(const char *fileName, uint8_t *buffer, uint16_t bufferSize, bool clearBuffer) { _printMessage("Reading file '%s'\n", fileName); if (clearBuffer) { memset(buffer, 0, bufferSize); } File file = _filesystem->open(fileName, FILE_READ); uint16_t fileSize = file.size(); // Sanity check if (!file || file.isDirectory()) { _printMessage("Failed to open file '%s'.\n", fileName); return false; } // check if the buffer is big enough if (bufferSize < fileSize) { _printMessage("Buffer size is too small for file '%s'.\n", fileName); file.close(); return false; } if (!file.available()) { _printMessage("File '%s' is empty.\n", fileName); } // size_t bytesRead = file.readBytes(buffer, fileSize); // read the data byte by byte for (size_t i = 0; i < fileSize; i++) { buffer[i] = file.read(); } file.close(); return true; } bool FileLibClass::remove(const char *fileName) { _printMessage("Removing file '%s'\n", fileName); if (!_filesystem->exists(fileName)) { _printMessage("File '%s' does not exist.\n", fileName); return false; } return _filesystem->remove(fileName); } bool FileLibClass::rename(const char *fileName, const char *newName, bool overwrite) { _printMessage("Renaming file '%s' to '%s'\n", fileName, newName); if (_filesystem->exists(newName) && !overwrite) { _printMessage("File '%s' already exists.\n", newName); return false; } return _filesystem->rename(fileName, newName); } bool FileLibClass::mkdir(const char *path) { _printMessage("Creating directory '%s'\n", path); if (_filesystem->exists(path)) { _printMessage("Directory '%s' already exists.\n", path); return false; } return _filesystem->mkdir(path); } uint64_t FileLibClass::getFreeSpace() { _printMessage("Getting free space\n"); if (_type == StorageType::FL_SPIFFS) { return LITTLEFS.totalBytes() - LITTLEFS.usedBytes(); } if (_type == StorageType::FL_MMC) { uint64_t cardSize = SD_MMC.totalBytes(); uint64_t usedSpace = SD_MMC.usedBytes(); if (usedSpace > cardSize) { _printMessage("ERROR: Used space is greater than card size \n"); return 0; } uint64_t freeSpace = cardSize - usedSpace; return freeSpace; } if (_type == StorageType::FL_SD) { uint64_t cardSize = SD.totalBytes(); uint64_t usedSpace = SD.usedBytes(); if (usedSpace > cardSize) { _printMessage("Error: Used space is greater than card size \n"); return 0; } uint64_t freeSpace = cardSize - usedSpace; return freeSpace; } return 0; } bool copy(File &source, File &dest) { if (!source || !dest) { return false; } int bufferSize = 512; char buffer[bufferSize]; while (source.available()) { int bytesRead = source.readBytes(buffer, bufferSize); int bytesWritten = dest.write((uint8_t *)&buffer, bytesRead); if (bytesWritten != bytesRead) { return false; } } dest.flush(); return true; } void FileLibClass::_printMessage(const char *message, ...) { if (_verbose) { // get the type name const char *typeName; switch (_type) { case FL_SPIFFS: typeName = "FL_SPIFFS"; break; case FL_SD: typeName = "FL_SD"; break; case FL_MMC: typeName = "FL_MMC"; break; default: typeName = "Unknown"; break; } char buffer[256]; va_list args; va_start(args, message); vsnprintf(buffer, sizeof(buffer), message, args); va_end(args); // switch for different storage types Serial.printf("%s: %s", typeName, buffer); } } //Create FileLibClass::exists function bool FileLibClass::exists(const char* fileName) { return _filesystem->exists(fileName); }