Skip to content

fileStreamReader

lolrobbe2 edited this page Aug 24, 2024 · 2 revisions

fileStreamReader

The fileStreamReader class is a specialized reader in the Athena library, designed for efficient reading of binary data from files. It extends the functionality provided by the base streamReader class, adding features specifically tailored for handling files with multiple compressed sections.

Overview

fileStreamReader is particularly useful for reading complex binary files that are divided into multiple sections. Each section can be independently compressed and decompressed, allowing for efficient reading of large files without needing to load the entire file into memory at once.

Key Features

  • File-Based Operations: Reads data from a specified file path using standard C++ file streams. This makes it suitable for use in a wide variety of file-based applications.

  • Section Management: Supports navigating between different sections of the file. This includes moving to the next or previous section, which is useful for files that are logically divided into separate parts.

  • Selective Decompression: Sections of the file are compressed and can be decompressed individually when accessed. This on-demand decompression improves performance and reduces memory usage by only decompressing sections as needed.

  • Data Handling:

    • Reading Raw Data: The class provides methods to read raw data from the current section (beware no safety mechanisms here).
    • Reading Objects: The class provides methods to read individual objects of trivially copyable types from the current section.
    • Reading Arrays: It also supports reading arrays of trivially copyable types, allowing for bulk data processing in a structured manner.
  • Stream Integrity: The class ensures that the stream is in a good state before performing any read operations. This helps prevent errors and ensures data integrity during file operations.

Methods

Stream Management

  • bool isStreamGood() const

    • Checks if the stream is in a good state for reading operations.
  • void setSectionPointerPosition(size_t index)

    • Sets the current section pointer to the specified index (where to read from inside the current section).
  • void setStreamPosition(size_t index)

    • Sets the current stream position to the specified index.

Section Management

  • void previousStreamSection()

    • Moves the section pointer to the previous section.
  • void nextStreamSection()

    • Moves the section pointer to the next section.
  • size_t getStreamSectionCount() const

    • Returns the total number of sections in the file.

Data Reading

  • const char* readData(size_t size)

    • Reads raw data of the specified size from the current section.
  • template<typename T> T& readObject()

    • Reads an object of type T from the current section.
  • template<typename T> std::vector<T>& readArray()

    • Reads an array of objects of type T from the current section.

For types that are not trivially copyable (e.g., std::string), you need to provide a custom deserialization function. The function should have the following signature:

template<typename T>
static T& deserialize(athena::buffer* buf);

the responsibility of COMPATIBILTY in this case falls upon the user not the library!

Examples

Reading Objects from a File

#include <athena.h>
#include <iostream>

struct MyData {
    int id;
    float value;
};

int main() {
    std::filesystem::path path = "./data.bin";
    athena::fileStreamReader streamReader(path);

    if (!streamReader.isStreamGood()) {
        std::cerr << "Failed to open file stream." << std::endl;
        return 1;
    }

    // Read an object of type MyData
    MyData data = streamReader.readObject<MyData>();
    std::cout << "ID: " << data.id << ", Value: " << data.value << std::endl;

    return 0;
}

Reading Arrays from a File

#include <athena.h>

struct MyData 
{
    int id;
    float value;
};

int main() {
    std::filesystem::path path = "./data.bin";
    athena::fileStreamReader streamReader(path);

    if (!streamReader.isStreamGood()) 
    {
        std::cerr << "Failed to open file stream." << std::endl;
        return 1;
    }

    // Read an array of MyData objects
    std::vector<MyData> dataArray = streamReader.readArray<MyData>();
    for (const auto& data : dataArray) 
        std::cout << "ID: " << data.id << ", Value: " << data.value << std::endl;
    

    return 0;
}

Navigating Sections

#include <athena.h>

struct MyData 
{
    int id;
    float value;
};

int main() 
{
    std::filesystem::path path = "./data.bin";
    athena::fileStreamReader streamReader(path);

    if (!streamReader.isStreamGood()) 
    {
        std::cerr << "Failed to open file stream." << std::endl;
        return 1;
    }

    // Navigate to the first section and read data
    streamReader.setSectionPointerPosition(0);
    MyData data = streamReader.readObject<MyData>();
    std::cout << "First section data: ID: " << data.id << ", Value: " << data.value << std::endl;

    // Move to the next section and read data
    streamReader.nextStreamSection();
    std::vector<MyData> dataArray = streamReader.readArray<MyData>();
    std::cout << "Next section data:" << std::endl;
    for (const auto& item : dataArray) {
        std::cout << "ID: " << item.id << ", Value: " << item.value << std::endl;
    }

    // Move to the previous section and read data again
    streamReader.previousStreamSection();
    data = streamReader.readObject<MyData>();
    std::cout << "Returned to previous section data: ID: " << data.id << ", Value: " << data.value << std::endl;

    // Move to a specific section by index and read data
    streamReader.setSectionPointerPosition(2);
    dataArray = streamReader.readArray<MyData>();
    std::cout << "Data in section 2:" << std::endl;
    for (const auto& item : dataArray) 
        std::cout << "ID: " << item.id << ", Value: " << item.value << std::endl;
    

    return 0;
}

Deserializing non trivial objects

#include <athena.h>
#include <string>

// Define a struct with non-trivially copyable types
struct MyStruct 
{
    int id;
    float value;
    std::string name; // Non-trivially copyable

    // Deserialization function for MyStruct
    static MyStruct deserialize(athena::buffer* buf) 
    {
        MyStruct obj;
        obj.id = *reinterpret_cast<const int*>(buf->readData(sizeof(obj.id))); // Read integer
        obj.value = *reinterpret_cast<const float*>(buf->readData(sizeof(obj.value))); // Read float

        size_t nameLength;
        buf->readData(reinterpret_cast<char*>(&nameLength), sizeof(nameLength)); // Read length of the string
        obj.name.resize(nameLength);
        buf->readData(&obj.name[0], nameLength); // Read string data

        return obj;
    }
};

int main()
{
    // Define the path to the file
    std::filesystem::path path = "data.bin";

    // Create a fileStreamReader
    athena::fileStreamReader reader(path);

    // Read the object from the file
    MyStruct readData = reader->readObject<MyStruct>()

    // Output the read data
    std::cout << "ID: " << readData.id << std::endl;
    std::cout << "Value: " << readData.value << std::endl;
    std::cout << "Name: " << readData.name << std::endl;
}

The fileStreamReader class is an essential part of the Athena library's file handling capabilities, offering efficient and flexible options for reading binary data from complex, multi-section files.