【问题标题】:ifstream doesn't load whole fileifstream 不加载整个文件
【发布时间】:2017-12-30 21:37:26
【问题描述】:

这个主题的名称可能不正确,但我不知道如何命名这个问题。 关于背景的东西,我正在编写一个游戏,它的 3d 表面被分成块。我想出了一种保存机制,其中所有块对象及其属性都以压缩形式保存到无序映射中,然后序列化到文件中,因此可以根据当前需求有效地加载和保存世界的某些部分。 当然,在加载时,文件被加载,反序列化为无序映射,字符串实时转换为块对象。 这是一个计划,但实现起来有困难。

我尝试了所有可能的搜索,但没有结果。在我玩测试的过程中,我写了一个这样的小测试脚本:

#include <iostream>
#include <fstream>
#include <sstream>

int main()
    {
    std::ifstream reader("output.dat", std::ios::binary);
    std::string data;
    reader>>data;
    reader.close();
    std::cout<<data.size()<<std::endl;

    std::stringstream ss;
    ss.str(data);

    unsigned char id_prefix=0, zone_prefix=1;
    while (ss.peek()!=EOF)
        {
        unsigned char type;
        ss>>type;
        if (type==id_prefix)
            {
            unsigned char tempx, tempy, tempz;
            unsigned short tempid;

            if (!(ss>>tempx)) std::cout<<"reading of x failed."<<std::endl;
            if (!(ss>>tempy)) std::cout<<"Reading of y failed"<<std::endl;
            if (!(ss>>tempz)) std::cout<<"Reading of z failed."<<std::endl;
            if (!(ss>>tempid)) std::cout<<"Reading of id failed, position is "+std::to_string(ss.tellg())+", values are "+std::to_string(type)+" "+std::to_string(tempx)+" "+std::to_string(tempy)+" "+std::to_string(tempz)<<std::endl;

            std::cout<<(int)tempx<<" "<<(int)tempy<<" "<<(int)tempz<<" "<<(int)tempid<<std::endl;
            }
        else if (type==zone_prefix)
            {
            unsigned char tempx, tempy, tempz;
            unsigned int tempzone;
            ss>>tempx;
            ss>>tempy;
            ss>>tempz;
            ss>>tempzone;
            std::cout<<(int)tempx<<" "<<(int)tempy<<" "<<(int)tempz<<" "<<(int)tempzone<<std::endl;
            }
        }

    }

Output.dat 是一个包含一个实验性解压缩块的文件,用于重现游戏中的解析过程。 您可以从以下位置下载它: https://www.dropbox.com/s/mljsb0t6gvfedc5/output.dat?dl=1 如果需要,它的大小约为 160 kb。这是第一个问题。 这可能只是我的愚蠢,但我认为当我使用 std::ios::binary 打开 ifstream,然后将其内容提取到字符串时,它会加载整个文件,但它只加载了前 46 个字节。 这是第一个问题,接下来在游戏中,我使用其他系统加载了有效的数据,但是从代码的下部可以看出,在这个位置附近的字符串流处理也失败了。 我猜数据也有问题,如您所见,格式是 uchar 类型(指示后面的字节是指 id 还是 zone)、坐标(每个都为 uchar),如果是 id,则为 ushort,如果是 zone 则为 uint。 但是当我用自己创建的二进制编辑器查看文件时,它只显示 id 一个字节,而不是我对短值所期望的两个。保存也是用 stringstream 完成的,形式为: 无符号短 tempid=3; //示例值 ss

在结果文件中,这表示为 51(一个字节),什么是 3 的 ascii 代码,所以我有点困惑,或者说是一点点。

你能帮我解决这个问题吗?我在 win7 64 位上使用 Mingw g++ 4.9.3。

非常感谢!

从 1.1.2017 开始编辑

现在整个文件都在 stringstream 中读取,但值的提取仍然失败。 当 >> 提取读取到下一个空格时,例如提取到无符号短的情况如何? 我正在玩代码位,试图将例如 unsigned short tempid 更改为 unsigned char tempid。 输出对我来说没有意义。 简而言之,字节如下: 0;1;0;0;51 被读取为类型 0、x 1、y 0、z 0 和 id 3 什么是正确的,即使我不明白为什么这里是 51 而不是 3。 之前写入流似乎是:

unsigned short idtowrite=3;
ss<<idtowrite;

但是当我将 unsigned short tempid 更改为 unsigned char tempid 时,它会将其读取为类型 0、x 1、y 0、z 0 和 id 51,这是不正确的,但我希望它来自写入的文件。 如果它通过完整流正确读取,我不会解决它,但由于某种原因,直到 0;8;0;0;51 一切都是正确的,从 0;9;0;0;51 开始,它旁边的失败,其中 x 读取为 0,y 读取为 0,z 读取为 51,并且设置了 EOF。 我在想如果阅读没有错过一个字节,但我没有理由这样做。 你能推荐我一些有效且可行的方法来将值存储在字符串流中吗?

提前致谢!

【问题讨论】:

  • reader&gt;&gt;data 最多读取第一次出现的空白字符。试试这个:std::stringstream ss; ss &lt;&lt; reader.rdbuf(); - 这应该将文件的全部内容吞入字符串流中。
  • 什么是“reader.close();”创建 sreader fstream 后立即?
  • 你所有的阅读都假设内容是文本,但事实并非如此。
  • 哦,谢谢! Rdbuf 变体完美运行。但是现在我对代码的第二部分有问题,从 stringstream 读取。我在为这篇文章添加扩展名时遇到了问题,只有在创建新问题后我才知道原因。对不起,这是我关于stackoverflow的第一个问题。您可以在stackoverflow.com/questions/48053097/… 找到新问题,感谢您的理解。

标签: c++


【解决方案1】:

std::ios::binary 仅具有抑制行尾转换的效果(例如,文件中的\r\n 不会仅转换为内存中的\n)。在处理二进制文件时提供这个当然是正确的。

但是,&gt;&gt; 仍然是一个格式化输入函数,它会跳过前导空格,在空格处终止等等。

如果您想实际将文件作为二进制数据读取,则必须在流对象上使用read 函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多