12

I have some code that uses ifstream to read some data from a file and everything works.

Now I wish, without modifying some code, read this data from a memory, actually I have a char * that contains the data...

How can I put my char * data into a ifstream without reading effectively the file?

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
ghiboz
  • 7,863
  • 21
  • 85
  • 131
  • Possible duplicate of [Setting the internal buffer used by a standard stream (pubsetbuf)](http://stackoverflow.com/questions/1494182/setting-the-internal-buffer-used-by-a-standard-stream-pubsetbuf) – Ciro Santilli OurBigBook.com Mar 31 '17 at 05:42

5 Answers5

16

Although use of std::istringstream (sometimes erronously referred to without the leading i; such a class does exist but is more expensive to construct, as it also sets up an output stream) is very popular, I think it is worth pointing out that this makes—at a minimum—one copy of the actual string (I'd suspect that most implementations create two copies even). Creating any copy can be avoided using a trivial stream buffer:

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

For a small area of memory, the difference may not matter, although the saved allocation can be noticable there, too. For large chunks of memory, it makes a major difference.

Justin
  • 24,288
  • 12
  • 92
  • 142
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
9

The standard library offers an in-memory istream that is also writeable: std::stringstream.

You need to properly abstract your code so that it accepts a generic istream instead of an ifstream, construct a stringstream, populate it with your data and pass that to the function.

For example:

const char* data = "Hello world";
std::stringstream str((std::string(data))); // all the parens are needed,
                                            // google "most vexing parse"

do_something_with_istream(str); // pass stream to your code
Jon
  • 428,835
  • 81
  • 738
  • 806
9

If the code that uses the ifstream& could be changed slightly to use an istream& then you could easily switch between ifstream and istringstream (for reading data from memory):

void read_data(std::istream& in)
{
}

Callers:

std::istringstream in_stream(std::string("hello"));
read_data(in_stream);

std::ifstream in_file("file.txt");
read_data(in_file);
hmjd
  • 120,187
  • 20
  • 207
  • 252
1

You may be searching for a stringstream. http://www.cplusplus.com/reference/sstream/stringstream/. I've only used that once before and it's been a long time, but basically you can stream from a location in memory.

Matthew
  • 3,886
  • 7
  • 47
  • 84
0

In my project I use the write() and read() methods of iostream, since I write binary data to a stringstream. Sorry, the following code is not tested and has probably syntax errors (typing from office... ;-), but something like this allows you to write to memory, files and elsewhere (e. g. network sockets):

void foo(std::iostream *mystream)
{
    mystream.write("Hello", 5);
    uint32_t i=5302523;
    mystream.write((char*) &i, sizeof i);
}

int main()
{
    // Write to memory. stringstream's write() and read() work binary
    std::stringstream memstream;
    foo(&memstream);

    // Write to file
    std::fstream f;
    try
    {
        f.open("file.dat");
        foo(&f);
    }
    catch (...)
    {
        // ...
    }

    if (f.is_open())
        f.close();

    return EXIT_SUCCESS;
}
wizard
  • 213
  • 1
  • 4
  • 8