【问题标题】:C++: Custom object serialization/deserialization failingC++:自定义对象序列化/反序列化失败
【发布时间】:2012-01-08 23:28:38
【问题描述】:

我在从存储的文件中读取序列化对象时遇到问题。 (见下面的代码)。

序列化过程“有效”,(尽管可能写得很糟糕),并且因为无法知道用户是否传递了 std::ios::binary 标志,所以我选择不使用格式化输出与whitespace。 (它还节省了内存,因为我没有丢失大量像素数据的潜力。)

我的第一次尝试看起来与示例相同,但 ints 是 unsigned chars,目的是将下半部分和上半部分打包成 chars,然后重新组装它们。

目前我可以将所有数据读取到文件中,但是当我尝试读取第一条非校验和数据时,它要么返回 0(在尝试使用 chars 的情况下)或垃圾(在这种情况下ints 的尝试)

序列化:

std::ostream& operator<<(std::ostream& os, const Sprite& data) {
    int dF = data._dimensions.first;
    int dS = data._dimensions.second;

    int cF = data._center.first;
    int cS = data._center.second;

    int fF = data._frameDimensions.first;
    int fS = data._frameDimensions.second;

    double sF = data._scaleDimensions.first;
    double sS = data._scaleDimensions.second;


    std::string name(*data._file);
    name.shrink_to_fit();
    os << 'S' << 'P' << 'R' << (name.length() + 1) << name.c_str() << dF << dS << cF << cS << fF << fS << sF << sS;
    for(int x = 0; x < data._dimensions.first; ++x) {
        for(int y = 0; y < data._dimensions.second; ++y) {
            int color = getpixel(data._image, x, y);
            os << static_cast<unsigned char>(getr(color)) << static_cast<unsigned char>(getg(color)) << static_cast<unsigned char>(getb(color));
        }
    }
    int tint = data._tint;
    os << static_cast<unsigned char>(getr(tint)) << static_cast<unsigned char>(getg(tint)) << static_cast<unsigned char>(getb(tint));
    os << data._tintIntensity << data._alpha;
    return os;
}

反序列化:

std::istream& operator>>(std::istream& is, Sprite& data) {
    char checksum[3];
    is >> checksum[0] >> checksum[1] >> checksum[2];
    if(checksum[0] != 'S' || checksum[1] != 'P' || checksum[2] != 'R') {
        is.setstate(std::ios::failbit);
        return is;
    }
    int name_length;
    is >> name_length;

    std::string name(name_length, '\0');

    for(int i = 0; i <= name_length; ++i) {
        char current_char = '\0';
        is >> current_char;
        name[i] = current_char;
    }

    int upper = 0;
    int lower = 0;
    is >> upper;
    is >> lower;
    data._dimensions.first = (upper << 8) | lower;

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._dimensions.second = ((upper << 8) | lower);

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._center.first = ((upper << 8) | lower);

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._center.second = ((upper << 8) | lower);

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._frameDimensions.first = ((upper << 8) | lower);

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._frameDimensions.second = ((upper << 8) | lower);

    double f = 0.0;
    double s = 0.0;
    is >> f >> s;
    data._scaleDimensions.first = f;
    data._scaleDimensions.second = s;

    destroy_bitmap(data._image);
    data._image = NULL;
    data._image = create_bitmap(data._dimensions.first, data._dimensions.second);
    for(int x = 0; x < data._dimensions.first; ++x) {
        for(int y = 0; y < data._dimensions.second; ++y) {
            unsigned char r = 0;
            unsigned char g = 0;
            unsigned char b = 0;
            is >> r >> g >> b;
            int color = ((r << 16)  | (g << 8) | b); //0xRRGGBB
            putpixel(data._image, x, y, color);
        }
    }
    unsigned char rtint = 0;
    unsigned char gtint = 0;
    unsigned char btint = 0;
    is >> rtint >> gtint >> btint;
    data._tint = ((rtint << 16)  | (gtint << 8) | btint); //0xRRGGBB

    is >> data._tintIntensity;
    is >> data._alpha;
    return is;
}

【问题讨论】:

  • 格式标志std::ios_base::binary与不进行格式化I/O有什么关系?这个标志仅仅决定了如何处理行尾序列:在非二进制模式下写入 `\n' 时,它可能会被替换(例如,被 CR/LF),而在二进制模式下它不会被替换。类似地,当读取行尾序列在非二进制模式下被单个 '\n' 替换或在二进制模式下保持原样时。为了防止用户使用或不使用此标志打开,您实际上应该使用格式化 I/O!
  • 查看代码:在不插入空格的情况下写入多个值将导致std::istream 读取一个大值而不是多个较小的值。可能较大的值会导致溢出错误,将流置于错误状态。这就是你的问题开始的地方......
  • @DietmarKühl:比一个答案,我会接受。 :D

标签: c++ serialization file-io binary-serialization


【解决方案1】:

反序列化不应该是这样的:

int upper = 0;
int lower = 0;
is >> upper;
is >> lower;
data._dimensions.first = upper;
data._dimensions.second = lower;

center 和 frameDimensions 类似

【讨论】:

    【解决方案2】:

    我会使用bitfileds。只是不要忘记在之前添加#pragma pack(1),在之后添加#pragma pack()。由于计算机只能寻址字节,因此您必须确保您的位域是8 的倍数。此外,位的打包取决于编译器/机器,因此您的阅读器应该使用相同的编译器进行编译。 然后只需使用例如:

    somefilestream.write(&some_bitfield_struct, sizeof(some_bitfield_struct));
    

    【讨论】:

      猜你喜欢
      • 2019-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多