Search code examples
c++stringstream

Reading a binary file in c++ with stringstream


I want to write/read data from a file. Is it possible to divide the file (inside the code) in multiple Strings/Sections? Or read data untill a specific line?

Just like: "Read the Data untill line 32, put it inside a String, read the next 32 lines and put it into another string"

Im already know how to read and find data with seekp but i dont really like it because my code always gets to long.

I already found some code but i dont understand it how it works:

dataset_t* DDS::readFile(std::string filename)
{
dataset_t* dataset = NULL;

std::stringstream ss;
std::ifstream fs;
uint8_t tmp_c;

try
{
    fs.open(filename.c_str(), std::ifstream::in);

    if (!fs)
    {
        std::cout << "File not found: " << filename << std::endl;
        return NULL;
    }

    while(fs.good())
    {
        fs.read((char*)&tmp_c, 1);
        if (fs.good()) ss.write((char*)&tmp_c, 1);
    }
    fs.close();

    dataset = new dataset_t();

    const uint32_t bufferSize = 32;
    char* buffer = new char[bufferSize];

    uint32_t count = 1;
    while(ss.good())
    {
        ss.getline(buffer, bufferSize);

        dataitem_t dataitem;
        dataitem.identifier = buffer;
        dataitem.count = count;
        dataset->push_back(dataitem);

        count++;
    }

    return dataset;
}
catch(std::exception e)
{
    cdelete(dataset);
    return NULL;
}

}

The Code edits a binary save file.

Or can someone link me a website where i can learn more about buffers and stringstreams?


Solution

  • You could create some classes to model your requirement: a take<N> for 'grab 32 lines', and a lines_from to iterate over lines.

    Your lines_from class would take any std::istream: something encoded, something zipped, ... as long as it gives you a series of characters. The take<N> would convert that into array<string, N> chunks.

    Here's a snippet that illustrates it:

    int main(){
        auto lines = lines_from{std::cin};
    
        while(lines.good()){
            auto chunk = take<3>(lines);
            std::cout << chunk[0][0] << chunk[1][0] << chunk[2][0] << std::endl;
        }
    }
    

    And here are the supporting classes and functions:

    #include <iostream>
    #include <array>
    
    class lines_from {
    public:
        std::istream &in;
        using value_type = std::string;
    
        std::string operator*() {
            std::string line;
            std::getline(in, line);
            return line;
        }
    
        bool good() const {
            return in.good();
        }
    };
    
    template<int N, class T>
    auto take(T &range){
        std::array<typename T::value_type, N> value;
        for (auto &e: value) { e = *range; }
        return value;
    }
    

    (demo on cpp.sh)