Как я могу прочитать двоичные данные из wfstream?

У меня небольшая проблема с чтением данных из файла. Я хочу иметь возможность читать wstring, а также кусок необработанных данных произвольного размера (размер в байтах).

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 *'

Возможно, я использую неправильные потоки или что-то в этом роде. По сути, я хочу прочитать wstring, за которым следует размер данных (который может быть любым количеством байтов), за которым следует столько байтов данных компонента. Очевидно, я не могу читать char, потому что шаблон предполагает wchar_t.

Я могу читать wchar_t, но тогда я должен убедиться, что данные хранятся в соответствии с sizeof(wchar_t). В противном случае я могу испортить поток. Сценарий был бы, когда данные составляют 15 байтов. Мне пришлось бы прочитать 16 байтов, затем замаскировать нежелательный байт, искать поток со смещением 15 байт (если возможно с шаблоном wchar_t?), Чтобы иметь возможность прочитать следующий фрагмент данных.

Очевидно, что должен быть более приятный способ добиться того, что я пытаюсь сделать.


person Statement    schedule 02.10.2008    source источник
comment
Это только я или кто-то еще читал WTFstream? :-)   -  person VVS    schedule 02.10.2008


Ответы (3)


проблема с stream.read заключается в том, что он использует wchar_t как «символьную единицу» с wfstream. Если вы используете fstream, он использует char как «символьную единицу».

Это сработает, если вы хотите читать широкие символы:

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

Также 15 байт данных не могут быть прочитаны широким потоком, потому что наименьшая единица имеет размер не менее 2 байт (см. ниже), поэтому вы можете читать только куски sizwof(wchar_t) * n.

Но если вас беспокоит переносимость приложения, wfstream/wchar_t, возможно, не лучшее решение, потому что не существует стандарта ширины wchar_t (например, в Windows wchar_t 16-битный, во многих системах unix/linux он 32-битный).

Вторая проблема с хранением текста в виде широких символов — порядок следования байтов, я бы предложил использовать UTF-8 для хранения текста.

person Fionn    schedule 02.10.2008
comment
Хорошие моменты. Некоторое время назад я полностью отказался от широких символов. Кодирование занимало слишком много времени, код стал непонятным, и мы решили, что не составит труда придерживаться обычных символов для строк. - person Statement; 02.10.2008
comment
Wifstream будет читать узкие символы из потока. (если вы не читаете необработанные символы, как вы предлагаете). Все ожидают, что он будет читать широкие символы, но на самом деле это не так. Вы можете читать UTF-8, используя wifstream и фасет codecvt, например, для преобразования в wchars. Работа с файлами UTF-16 сложнее, чем вы думаете. - person Pete; 27.04.2012

Учитывая ваши требования, я не думаю, что wfstream - это то, что вам нужно. Рассмотрите возможность использования чего-то вроде следующего фрагмента кода.

#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;
}

Это выводит:

hello
0x10
0x20
0x30
person Jorge Ferreira    schedule 02.10.2008
comment
Я полагаю, что изменение методологии очень помогает. Спасибо за фрагменты. - person Statement; 02.10.2008

# 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) )

Я думаю, что _T("filename.bin") и tfstream - это выражение пользовательского интерфейса; буфер и read() - это выражение DATA LOGIC. wfstream НЕ ДОЛЖЕН ограничивать буфер типом wchar_t. Пользовательский интерфейс НЕ ДОЛЖЕН смешиваться с DATA LOGIC! wfstream делает что-то неправильно здесь

person Jac08in    schedule 15.01.2014