4

I have an object that writes binary data to a file. Sometimes it needs to seek to the beginning and re-write some data, to update a header of instance. I now need to avoid file i/o, so I am looking for something equivalent to a "virtual" file stream that I could seek around with.

Right now I am using a vector, but I switched from a file to improve performance as much as absolutely possible in the first place. I am also having logical problems trying to imitate fseek with a vector.

Is there a better object to use in C++? My use case is

MyVirtualStream vs; vs.Write(somebytes); vs.Write(somebytes); vs.Seek(0); vs.Read(&somestruct); somestruct.data = 555; vs.Write(struct); vs.Seek(0 + sizeof(somestruct)); 
4
  • If you already have the object in memory, why not modify it (or a copy of it) directly and then write the file at the end? Trying to do all this through a file-like API seems like a massive headache. Commented Jul 23, 2020 at 13:39
  • You could write into a std::stringstream and dump its contents (std::stringstream::str()) to a file at once when you're done. (std::string is well prepared to handle binary data as well as text.) Commented Jul 23, 2020 at 13:40
  • @0x5453 When writing binary files, it may happen that you have to encode your data resulting in a final block size you have to denote at the beginning of the block but you don't know it before the encoding is completed. (I already saw binary files where this is the case and I stumbled myself into this issue when writing my own creations of binary files.) So, patching the block size afterwards appeared as only solution to me although this "rewinding" and overwriting is annoying e.g. when writing to network drives (concerning performance). Commented Jul 23, 2020 at 13:44
  • The alternative would be to make a "dry-run" before writing actual data. This might safe memory (no buffer needed) but I'm not sure whether it's so much faster. From maintenance aspect, it would scare me as I had to ensure that the "dry-run" results in the precise same sizes than the actual writing. Commented Jul 23, 2020 at 13:52

2 Answers 2

2

You could use std::stringstream:

NOTE: Read and write position seekg and seekp is independent for std:stringstream, but are interchangeable for file streams. In other words, there is only one pointer maintained for files.

#include <sstream> #include <iostream> struct Header { int flag1; char flag2; }; // Also you can provide an overload for `std::ostream::operator<<` like std::ostream& operator<<(std::ostream& out, Header& h) { out.write(reinterpret_cast<char*>(&h), sizeof(Header)); return out; } std::istream& operator>>(std::istream& in, Header& h) { Header header; in.read( reinterpret_cast<char*>(&header), sizeof(Header) ); h = std::move(header); return in; } int main(int argc, char *argv[]) { std::stringstream ss; Header h {0x30303030, 0x31}; Header h2 {0x32323232, 0x33}; std::string str = "Hello, world"; ss << str; ss.seekp(0); // move write position. ss.write("Buy ", 5); std::cout << ss.str() << std::endl; ss.write(reinterpret_cast<char*>(&h), sizeof(Header)); ss.seekg(5); // move read position ss.read(reinterpret_cast<char*>(&h2), sizeof(Header)); return 0; } 
Sign up to request clarification or add additional context in comments.

Comments

0

You're looking for a stringstream.

It's a stream, backed by a string (instead of a file or other thing).

Comments