views:

1431

answers:

2

Hello world!

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  A: 

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
smink
I suppose changing methodology helps out a great deal. Thanks for the snippets.
Statement
+1  A: 

Hi,

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.

Fionn
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.
Statement