3

I found some good results on reading e.g.: Read txt with iterators and preallocation, or read into containers. So I wondered how would I write most elegant a std::string into a file?

Edit: When reading I can preallocate space for the string via seek and tellg, since I know the size of the string, how could I tell the filesystem how much I want to write?

Community
  • 1
  • 1
math
  • 7,734
  • 10
  • 50
  • 60

3 Answers3

6

Here's a tiny example on how to output a std::string, but you should really read up on fstream

#include <iostream>
#include <fstream>
#include <string>

int main(int argc, char *argv[])
{

  std::string s("writemeout");
  std::ofstream outfile("output.txt");
  if(!outfile.is_open()) {
    std::cerr << "Couldn't open 'output.txt'" << std::endl;
    return -1;
  }

  outfile << s << std::endl;
  outfile.close();
  return 0;
}
Mahmoud Abdelkader
  • 19,043
  • 5
  • 37
  • 52
1

You can use the appropriate overload of the operator<< function to write a string to an std::ofstream object. Here's an example:

#include <fstream>
#include <string>

int main() {
    std::string s( "Hello, World!" );
    std::ofstream f( "hello.txt" );
    if ( !f.fail() )
        f << s;
}
Frerich Raabe
  • 81,733
  • 18
  • 105
  • 196
1

The main issue is that the process doesn't reverse perfectly.

std::ofstream ofs; // presumed open
ofs << v1 << v2 << v3 << v4 << v5; // some different variables
ofs.close();

std::ifsteram ifs; // open to same stream
ifs >> r1 >> r2 >> r3 >> r4 >> r5; // variables of same types as above

You might think that will work but probably won't. There are no formal delimiters when writing to a text stream, you have to manually insert them to know when one token ends and another begins.

Usually with regards to strings, it is assumed that they contain no newline characters or no tab characters, and then when reading back, these are often used as a delimiter.

The most "perfect" way to write a string so you can read it back is to write its size then its content. Even then if you use iostream:

os << str.size() << str;

will not put any space between the size and the content, so if the content begins with a digit you are in trouble when reading it back later.

os << str.size() << '\t' << str;

will work.

With regards to reading big collections, your best bet with strings is to have tab-separated or line-separated and use std::getline in a loop. istream_iterator will simply not work if any of your strings have spaces.

Your alternative is to first read in a header section with: - number of strings - size of each string.

Then read in the data just from a big buffer, and by knowing how many you are about to read and their sizes, you can pre-allocate your buffers.

Writing binary means writing raw bytes to the file. This is similar to the fwrite function in C, except you do not specify two sizes, just one size which is the number of bytes you will write.

You need to address issues that: - Windows will insert an ASCII 13 character for you in front of every ASCII 10 character you write if you do not open the stream for binary. - If you are writing numbers byte-wise, beware of endian and size issues if they will be read back. The best way to address this is to put the endian-ness in the header section of your output and then write in native format. The assumption is that most of the time this will be the platform you use so it is more efficient.

int x;
os.write( &x, sizeof(int) );

The big plus-side of writing numbers this way is not only is it more efficient in time but there is also no need to insert any kind of delimiter so reading them back becomes relatively simple.

The downside is that you will need a special interpreter to read the file back if there are any errors in it.

Anyway, these are the issues.

The elegant solution to all this is provided as part of the boost library with archive and serialize.

You can write in text or binary mode and it will restore the way you stored it. It will even write pointers "deeply" for you.

CashCow
  • 29,087
  • 4
  • 53
  • 86