0

I'm trying to use std::wofstream/wifstream to serialize/deserialized mixed numerical (e.g., int, double) and std::wstring content, with the numerical values serialized in binary mode. But the following code produces erroneous results:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    wofstream wos("Test.dat", std::ios_base::binary);

    int x1 = 100;
    double d1 = 50.0;
    wstring ostr(L"my string");

    wos.write(reinterpret_cast<wchar_t*>(&x1), sizeof(x1) / sizeof(wchar_t));
    wos.write(reinterpret_cast<wchar_t*>(&d1), sizeof(d1) / sizeof(wchar_t) );
    wos << ostr;

    wos.close();

    int x2 = 0;
    double d2 = .0;
    wstring istr;
    wifstream wis("Test.dat", std::ios_base::binary);

    wis.read(reinterpret_cast<wchar_t*>(&x2), sizeof x2 / sizeof(wchar_t));
    wis.read(reinterpret_cast<wchar_t*>(&d2), sizeof d2 / sizeof(wchar_t));
    wis >> istr;
    wis.close();
    wcout << x2 << "\n" << d2 << "\n" << istr << "\nistr.size() = " << istr.size() << endl;

    return 0;
}
**Expected output:**
100
50
my string
istr.size() = 9

**Actual output:**
100
0

istr.size() = 0

So, the double value and wstring are corrupted. The code works properly when serializing only the wstring (using <<) and not the binary numericals, or when using ofstream, ifstream and string rather than their wide-character equivalents. I suspect the problem lies in writing and reading in the int and double in two-byte chunks, but I'm at loss as to why. Advice appreciated.

--- EDIT ---

Thanks to everyone for the answers. I'd been using Qt's QDataStream to write these kinds of files without issue, but that abstracted away the problems that surfaced above. Takeaway is to stick with ifstream/ostream or, better yet, use a library (whether Qt's or the others suggested).

7
  • At least on Windows, wos.write attemps to convert each wchar_t element to the system default codepage. It just so happens that byte pairs in the byte representation of x1 are in the ASCII range, but bytes in d1 representation are not. If you examine the file, it's like 5 bytes large - the second write call fails midway, wos is marked with badbit, and the string output is not even attempted. Commented Jul 31 at 19:49
  • 2
    Advice appreciated. -- Visually inspect the file you created with a binary file viewer or editor. Are the results of when you view the file expected? Commented Jul 31 at 19:50
  • 1
    Note you're making implicit assumptions on the writer and reader of the file to have the same integer length and endianness. In general I advice you NOT to go the way of binary serialization unless you're really really sure you know what you are doing. Read this C++ Serialization and Unserialization. But in general just use a 3rd partly library for this (flatbuffers/protobuf), or serialize using some well know text format like json or xml (excellent libs for those too) Commented Jul 31 at 19:55
  • I believe this is by design. write ultimately calls std::basic_filebuf<CharT,Traits>::overflow on each character, and that one is documented to "... use std::codecvt::out of the imbued locale to convert the characters into external (possibly multibyte) representation...". Opening the file in binary mode doesn't do what you think it does (roughly, text vs binary mode makes no difference on Linux-y systems; on Windows, it suppesses conversion of \n character to CR LF pair). Commented Jul 31 at 19:58
  • 2
    TL;DR is that wofstream is simply not suitable for writing binary data. Commented Jul 31 at 20:00

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.