Search code examples
c++filebufferistream

How to read from RAM?


What I need to do?

I need to read the file from RAM

How I am doing it?

I use std::istream, because it know how to read from buffer. So, there is method that know how to read file size(according to this SO answer https://stackoverflow.com/a/6039648/5709159)

long getFileSize(const std::string &filename)
{
    struct stat stat_buf{};
    int rc = stat(filename.c_str(), &stat_buf);
    return rc == 0 ? stat_buf.st_size : -1;
}

Then I use membuf to copy bytes from file to buffer (according to this SO answer https://stackoverflow.com/a/13586356/5709159)

struct membuf : std::streambuf
    {
        membuf(char *base, std::ptrdiff_t n)
        {
            this->setg(base, base, base + n);
        }
    };

Full implementation looks like this

long size = getFileSize(filename);
membuf sbuf(0, size);
std::istream file(&sbuf);

But, I am now sure that sbuf(0, size); that 0 here is on the right place...

So, question is - how to set membuf with right size ?


Solution

  • Option 1

    Expanding on the code in your question:

    long size = getFileSize(filename);
    std::vector<char> buffer(size);
    // here fill the buffer with data
    membuf sbuf(buffer.data(), buffer.size());
    std::istream file_from_ram(&sbuf);
    

    if you'd like to fill the buffer with contenst of some file, do this:

    std::istream original_file("filename.dat");
    original_file.read(buffer.data(), size);
    

    Note: this method has problems. First, as @andrew-henle mentioned in comments, file size of type off_t which may not fil into long. Second, this method suffers from TOCTOU (time of check -- time of use) problem: if file size changes between the call to getFileSize and reading the file, you may be in trouble.

    Option 2

    Use std::istringstream instead:

    std::string buffer;
    // here fill the string with data
    std::istringstream file_from_ram(buffer);
    

    If you'd like to fill the buffer with contents of some file, do this (from https://stackoverflow.com/a/116220/4451432):

    std::ifstream original_file("filename.dat");
    
    std::istringstream file_from_ram;
    file_from_ram << original_file.rdbuf();
    // Now you can read from file_from_ram