【问题标题】:ifstream extraction operator not workingifstream 提取运算符不工作
【发布时间】:2014-05-01 08:17:37
【问题描述】:

我正在尝试使用以下代码从二进制文件中读取数据:

fstream s;
s.open(L"E:\\test_bin.bin", ios::in | ios::binary);
int c = 0;
while (!s.eof())
{
    s >> c;
    cout << c;
}

c 始终为 0(c 的当前值。如果我将 c 设置为 1,则结果为 1)。文件存在并且它的数据不是零,所以问题不在文件中。我可以使用 fread 和 s.get() 读取这个文件,但是为什么给定的代码不起作用?

【问题讨论】:

  • 在打开文件后放置一个if(s)来检测错误(同样while (!s.eof())是错误的)
  • 从二进制文件中读入后,你期望 'c' 包含什么?一大块比特还是一个完整的数字?
  • 它仍然什么也没读,但正如我提到的,文件没问题,可以成功打开。
  • 当然是大块的。

标签: c++ iostream


【解决方案1】:

使用ios::binary 标志并不一定意味着您可以读写二进制数据。看看https://stackoverflow.com/a/2225612/2372604ios::binary 表示“数据被读取或写入而不翻译......”

您可能想要做的是使用s.read(...)。在您的情况下,流运算符尝试读取一个完整的整数(类似于“1234”),而不是 X 位数,以适合您的整数。

对于读取 4 个字节,类似下面的方法可能有效(未经测试):

int n;
while (s.read((char*) &n, 4) && s.gcount() != 0 ) {}

【讨论】:

  • 我需要读取完整的 4 个字节。你的意思是我不能使用 >> 从文件中读取字节?
  • "数据被读取或写入而不翻译..."是二进制流的定义
  • 这当然是不正确的。循环应该是while ( s.read((char*n)&amp;n, 4) &amp;&amp; s.gcount() != 0 ) {}。除了它仍然只是将原始字节读入int,这是永远不对的。
  • @JamesKanze 谢谢,我有点太仓促了。
  • @user657267 始终会创建 sentry 对象,即使对于 s.read 也是如此。不同之处在于,对于&gt;&gt;(除非目标是streambuf*),哨兵参数使用ios_base 中的skipws 标志进行初始化;对于非格式化输入,它使用常量noskipws 进行初始化,而不管ios_base 中的标志状态如何。
【解决方案2】:

有什么问题:

int c = 0;
char ch;
int shift = 32;
while ( s.get( ch ) && shift != 0 ) {
    shift -= 8;
    c |= (ch & 0xFF) << shift;
}
if ( shift != 0 ) {
    //  Unexpected end of file...
}

这是(或多或少)读取二进制 32 位的标准方式 网络外的整数。 (这假设原生 int 是 当然是 32 位 2 的补码。)

一些协议使用不同的 32 位整数表示,并且 所以需要不同的代码。

至于你的原始代码:测试s.eof()总是错的, &gt;&gt; 用于输入文本;特别是,它会跳过 前导空格(和二进制数据可能包含代码 对应于空格)。

我还可以补充一点,您应该确保流是 充满"C" 语言环境,因此无需代码翻译 发生。

【讨论】:

  • 那不会以 Big Endian 格式读取 int 吗? @詹姆斯
  • 在大多数网络协议中,整数是大端。这几乎是一个标准。 (在某种程度上相当令人惊讶,因为大多数早期协议都是在小端的 DEC 处理器上开发的。)
猜你喜欢
  • 2015-01-12
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
  • 1970-01-01
  • 2018-12-09
  • 2013-07-12
相关资源
最近更新 更多