Запись объекта класса в файл с использованием потоков

У меня есть этот код для сериализации / десериализации объектов класса в файл, и, похоже, работает. Однако у меня есть два вопроса.

  1. Что делать, если вместо двух wstring's (как у меня сейчас) я хочу иметь один wstring и один string переменная-член в моем классе? (Я думаю, что в таком случае мой код не будет работать?).
  2. Наконец, ниже, в основном, когда я инициализирую s2.product_name_= L"megatex"; если вместо мегатекса я напишу что-нибудь по-русски, скажем (например, s2.product_name_= L"логин"), код больше не будет работать так, как задумано.

Что может быть не так? Благодарю.

Вот код:

// ConsoleApplication3.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>      // std::ifstream
using namespace std;

// product
struct Product
{
    double price_;
    double product_index_;
    wstring product_name_;
    wstring other_data_;

    friend std::wostream& operator<<(std::wostream& os, const Product& p)
    {
         return os << p.price_ << endl
                  << p.product_index_ << endl
                  << p.product_name_ << endl  
                  << p.other_data_ << endl;
    }

    friend wistream& operator>>(std::wistream& is, Product& p)
    {
        is >> p.price_ >> p.product_index_;
        is.ignore(std::numeric_limits<streamsize>::max(), '\n');

        getline(is,p.product_name_);
        getline(is,p.other_data_);

        return is;
    }
};

 int _tmain(int argc, _TCHAR* argv[])
{
    Product s1,s2;

    s1.price_ = 100;
    s1.product_index_ = 0;
    s1.product_name_= L"flex";
    s1.other_data_ = L"dat001";

    s2.price_ = 300;
    s2.product_index_ = 2;
    s2.product_name_= L"megatex";
    s2.other_data_ = L"dat003";

    // write
    wofstream binary_file("c:\\test.dat",ios::out|ios::binary|ios::app);
    binary_file << s1 << s2;
    binary_file.close();

    // read
    wifstream binary_file2("c:\\test.dat");

    Product p;
    while (binary_file2 >> p)
    {
        if(2 == p.product_index_){
            cout<<p.price_<<endl;
            cout<<p.product_index_<<endl;
            wcout<<p.product_name_<<endl;
            wcout<<p.other_data_<<endl;
        }
    }

    if (!binary_file2.eof())
         std::cerr << "error during parsing of input file\n";
    else
        std::cerr << "Ok \n";

    return 0;
}

1 ответ

Что если вместо двух wstring (как у меня сейчас) я хочу, чтобы в моем классе была одна переменная wstring и одна строковая переменная-член? (Я думаю, что в таком случае мой код не будет работать?).

Есть определитель, определенный для char * для любого basic_ostream (ostream а также wostream), так что вы можете использовать результат c_str() вызов функции-члена для string член. Например, если string участник other_data_:

 return os << p.price_ << endl
           << p.product_index_ << endl
           << p.product_name_ << endl  
           << p.other_data_.c_str() << endl;

Случай экстрактора является более сложным, так как вам придется читать как wstring и преобразовать в string, Самый простой способ сделать это просто читать как wstring а затем сужение каждого символа:

wstring temp;
getline(is, temp);
p.other_data_ = string(temp.begin(), temp.end());

Я не использую локали в этом примере, я просто преобразовываю последовательность байтов (8 бит) в последовательность слов (16 бит) для вывода и противоположных (усеченных значений) для ввода. Это нормально, если вы используете ASCII-символы или однобайтовые символы и вам не требуется определенный формат (как Unicode) для вывода.

В противном случае вам нужно будет справиться с locales. locale предоставляет культурную контекстную информацию для интерпретации строки (помните, что это просто последовательность байтов, а не символов в смысле букв или символов; карта между байтами и символом определяется locale). locale не очень простая в использовании концепция (человеческая культура не слишком). Как вы предполагаете, было бы лучше сначала провести небольшое исследование о том, как это работает.

Во всяком случае, идея заключается в следующем:

  1. Определите кодировку, используемую в строке, и кодировку, используемую в файле (Unicode или utf-16).
  2. Преобразовать strings из оригинальной кодировки в Unicode, используя locale для вывода.
  3. Преобразовать wstringчитать из файла (в Unicode) в stringс помощью locale,

Наконец, ниже, в основном, когда я инициализирую s2.product_name_= L"megatex"; если вместо мегатекса я напишу что нибудь по русски скажу (например, s2.product_name_= L"логин"), код больше не работает как задумано.

Когда вы определяете массив wchar_t с помощью L""вы на самом деле не указываете, что строка является Unicode, просто массив состоит из символов, а не wchar_t. Я предполагаю, что предполагаемая работа s2.product_name_ сохранить имя в формате Unicode, но компилятор примет все char в этой строке (как без L) и преобразовать в wchar_t просто заполнение нулями самого значимого байта. Unicode не очень хорошо поддерживается в стандарте C++ до C++11 (и все еще не слишком поддерживается). Это работает только для символов ASCII, потому что они имеют одинаковую кодировку в Unicode (или UTF-8).

Для использования символов Unicode в статической строке вы можете использовать escape-символы: \uXXXX, Я знаю, что делать это для каждого неанглийского персонажа не очень удобно. Вы можете найти список символов Unicode на нескольких сайтах в Интернете. Например, в Википедии: http://en.wikipedia.org/wiki/List_of_Unicode_characters.

Другие вопросы по тегам