C++ FAQ Celebrating Twenty-One Years of the C++ FAQ!!!
(Click here for a personal note from Marshall Cline.)
Section 36:
[36.5] How exactly do I read/write simple types in human-readable ("text") format?

Before you read this, make sure to evaluate all the tradeoffs between human-readable and non-human-readable formats. The tradeoffs are non-trivial, so you should resist a knee-jerk reaction to do it the way you did it on the last project — one size does not fit all.

After you have made an eyes-open decision to use human-readable ("text") format, you should remember these keys:

  • You probably want to use iostream's >> and << operators rather than its read() and write() methods. The >> and << operators are better for text mode, whereas read() and write() are better for binary mode.
  • When storing numbers, you'll probably want to add a separator to prevent items from running together. One simple approach is to always add a space (' ') before each number, that way the number 1 followed by the number 2 won't run together and look like a 12. Since the leading space will automatically get soaked up by the >> operator, you won't have to do anything explicit to extract the leading space in the code that reads things back in.
  • String data is tricky because you have to unambiguously know when the string's body stops. You can't unambiguously terminate all strings with a '\n' or '"' or even '\0' if some string might contain those characters. You might want to use C++ source-code escape-sequences, e.g., writing '\' followed by 'n' when you see a newline, etc. After this transformation, you can either make strings go until end-of-line (meaning they are deliminated by '\n') or you can delimit them with '"'.
  • If you use C++-like escape-sequences for your string data, be sure to always use the same number of hex digits after '\x' and '\u'. I typically use 2 and 4 digits respectively. Reason: if you write a smaller number of hex digits, e.g., if you simply use stream << "\\x" << hex << unsigned(theChar), you'll get errors when the next character in the string happens to be a hex digit. E.g., if the string contains '\xF' followed by 'A', you should write "\x0FA", not "\xFA".
  • If you don't use some sort of escape sequence for characters like '\n', be careful that the operating system doesn't mess up your string data. In particular, if you open a std::fstream without std::ios::binary, some operating systems translate end-of-line characters.
  • Another approach for string data is to prefix the string's data with an integer length, e.g., to write "now is the time" as 15:now is the time. Note that this can make it hard for people to read/write the file, since the value just after that might not have a visible separator, but you still might find it useful.

Please remember that these are primitives that you will need to use in the other FAQs in this section.