6

I have a slight problem reading data from file. I want to be able to read wstring's, aswell as a chunk of raw data of arbitrary size (size is in bytes).

std::wfstream stream(file.c_str());

std::wstring comType;
stream >> comType;

int comSize;
stream >> comSize;

char *comData = new char[comSize];
memset(comData, 0, comSize);
stream.read(comData, comSize); 
//error C2664 : 'std::basic_istream<_Elem,_Traits>::read' 
//            : cannot convert parameter 1 from 'char *' to 'wchar_t *'

Perhaps I am using wrong streams, or something along those lines. Basically, I want to read a wstring, size of the data followed (which could be any number of bytes), followed by that many bytes of component data. Obviously, I can't read char's because the template assumes wchar_t's.

I can read wchar_t's but then I have to make sure the data is stored as aligned by sizeof(wchar_t). Otherwise, I could end up corrupting the stream. A scenario would be when the data is 15 bytes. I would have to read 16 bytes, then mask the unwanted byte, seek the stream to 15 bytes offset (if possible with wchar_t templated?) to be able to read the next data chunk.

Clearly, there should be a nicer way of achieving what I am trying to do.

1
  • 2
    Is it just me or did somebody else also read WTFstream? :-) Commented Oct 2, 2008 at 13:56

3 Answers 3

2

Considering your requirements I do not think wfstream is the way to go. Considerer using something like the following code snippet.

#include "stdafx.h"
#include <fstream>
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    std::wstring str(L"hello");
    size_t size1 = str.length();
    char data[] = { 0x10, 0x20, 0x30 };
    size_t size2 = 3;

    FILE* output = NULL;
    if (_wfopen_s(&output, L"c:\\test.bin", L"wb") == 0) {
        fwrite(&size1, sizeof(size_t), 1, output);
        fwrite(str.c_str(), size1 * sizeof(wchar_t), 1, output);
        fwrite(&size2, sizeof(size_t), 1, output);
        fwrite(data, size2, 1, output);

        fclose(output);
    }

    FILE* input = NULL;
    if (_wfopen_s(&input, L"c:\\test.bin", L"rb") == 0) {
        fread(&size1, sizeof(size_t), 1, input);
        wchar_t* wstr = new wchar_t[size1 + 1];
        fread(wstr, size1 * sizeof(wchar_t), 1, input);
        std::wstring str(wstr, size1);
        delete[] wstr;
        fread(&size2, sizeof(size_t), 1, input);
        char* data1 = new char[size2];
        fread(data1, size2, 1, input);

        std::wcout << str.c_str() << std::endl;
        for (size_t i = 0; i < size2; ++i) {
            std::wcout << std::hex << "0x" << int(data1[i]) << std::endl;
        }

        delete[] data1;

        fclose(input);
    }

    return 0;
}

This outputs:

hello
0x10
0x20
0x30
Sign up to request clarification or add additional context in comments.

1 Comment

I suppose changing methodology helps out a great deal. Thanks for the snippets.
2

the problem with the stream.read is that it uses wchar_t as "character unit" with wfstream. If you use fstream it uses char as "character unit".

This would work if you want to read wide characters:

wchar_t *comData = new wchar_t[comSize];
stream.read(comData, comSize);

Also 15 bytes of data can't be read with a wide stream, because the smallest unit is at least 2bytes (see below), so you can only read chunks of sizwof(wchar_t) * n.

But if you are concerned about portability of the application wfstream/wchar_t is maybe not the best solution because there is no standard how wide wchar_t is (e.g. on windows wchar_t is 16bit on many unix/linux systems it is 32bit).

The second problem with storing text as wide characters is endianess, i would suggest to use UTF-8 for text storage.

2 Comments

Good points. I abandoned wide chars all together some time ago. Coding took too much time, code became unclear, and we decided it wasn't much of a problem to stick with regular chars for strings.
The wifstream will read narrow chars from the stream. (unless you read raw chars, as you suggest). Everyone expects it to read wide chars, but the reality is that it doesn't. You can read UTF-8 using a wifstream and a codecvt facet to convert to wchars, for example. Handling UTF-16 files is more complicated than you'd think.
0
# ifdef UNICODE
#     define tfstream wfstream
# else
#     define tfstream fstream
# endif

tfstream fs( _T("filename.bin"), tfstream::binary );
byte buffer[1023];
fs.read( buffer, sizeof(buffer) )

I think, the _T("filename.bin") and tfstream are the UI expression; the buffer and the read() is DATA LOGIC expression. wfstream must NOT restrict the buffer to the type wchar_t. The UI must NOT mix with DATA LOGIC ! wfstream do the wrong thing here

Comments

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.