The UFZ::Application contains an instance of the UFZ::Filesystem class, which is used to make interacting with the Flipper Zero filesystem easier.

Getting a reference to the filesystem

You can get a reference to UFZ::Filesystem by calling UFZ::Application::getFilesystem. The Filesystem class looks like this:

class Filesystem
{
public:
    FS_Error timestamp(const char* path, uint32_t* timestamp) const noexcept;
    FS_Error stat(const char* path, FileInfo* fileInfo) const noexcept;
    bool exists(const char* path) const noexcept;
    FS_Error remove(const char* path) const noexcept;

    FS_Error rename(const char* oldPath, const char* newPath) const noexcept;

    FS_Error copy(const char* oldPath, const char* newPath) const noexcept;
    FS_Error merge(const char* oldPath, const char* newPath) const noexcept;
    FS_Error migrate(const char* source, const char* destination) const noexcept;

    FS_Error mkdir(const char* path) const noexcept;
    FS_Error filesystemInfo(const char* path, uint64_t* totalSpace, uint64_t* freeSpace) const noexcept;

    void resolvePathAndEnsureAppDirectory(FuriString* path) const noexcept;

    bool areEquivalent(const char* path1, const char* path2, bool bTruncate) const noexcept;

    [[nodiscard]] static const char* getErrorDescription(FS_Error error) noexcept;

    FS_Error SDCardInfo(SDInfo* info) const noexcept;
    [[nodiscard]] FS_Error SDCardStatus() const noexcept;

    bool removeSimple(const char* path) const noexcept;
    bool removeRecursiveSimple(const char* path) const noexcept;
    bool mkdirSimple(const char* path) const noexcept;
    void getNextFilename(const char* dirname, const char* filename, const char* fileExtension, FuriString* nextFilename, uint8_t maxLength) const noexcept;
};

The different methods correspond to the storage_* C functions that can be found here.

Files

The UFZ::File class allows you to interact with files, including reading and writing to them. It looks like this:

class File
{
public:
    File(const UFZ::Filesystem& store, const char* path, FS_AccessMode accessMode, FS_OpenMode openMode) noexcept;
    bool open(const UFZ::Filesystem& store, const char* path, FS_AccessMode accessMode, FS_OpenMode openMode) noexcept;
    
    bool isOpen() noexcept;
    bool isDirectory() noexcept;

    size_t read(void* buffer, size_t bytesToRead) noexcept;
    template<typename T>
    size_t read(std::vector<T>& buffer, size_t chunkSize = 128) noexcept;

    size_t write(void* buffer, size_t bytesToWrite) noexcept;
    template<typename T>
    size_t write(const std::vector<T>& buffer) noexcept

    bool seek(uint32_t offset, bool bFromStart) noexcept;
    uint64_t tell() noexcept;
    bool truncate() noexcept;
    uint64_t size() noexcept;

    bool sync() noexcept;
    bool eof() noexcept;

    static bool copyToFile(File& source, File& destination, size_t size) noexcept;
    void close() noexcept;
    ~File() noexcept;
};

The functions are self-explanatory in what they do. For further documentation, refer to storage_file_* C functions on the flipper docs.

Note

When reading, make sure you're managing your memory correctly, as running out of memory is not an uncommon occurrance on large files.

Directories

Similar to UFZ::File, the UFZ::Directory class allows you to interact with directories. It looks like this:

class Directory
{
public:
    bool open(File& f, const char* path) noexcept;
    bool close() noexcept;

    bool read(FileInfo* info, char* name, uint16_t nameLength) noexcept;
    bool rewind() noexcept;
};

Reading on a directory allows you to iterate its contents.