逐字节读取二进制 istream
Posted
技术标签:
【中文标题】逐字节读取二进制 istream【英文标题】:Reading binary istream byte by byte 【发布时间】:2011-07-27 16:17:01 【问题描述】:我试图使用 ifstream 逐字节读取二进制文件。我之前使用过像 get() 这样的 istream 方法来一次读取二进制文件的整个块而没有问题。但我目前的任务是逐字节进行,并依靠 io 系统中的缓冲来提高效率。问题是我似乎比我应该早几个字节到达文件末尾。于是我写了如下测试程序:
#include <iostream>
#include <fstream>
int main()
typedef unsigned char uint8;
std::ifstream source("test.dat", std::ios_base::binary);
while (source)
std::ios::pos_type before = source.tellg();
uint8 x;
source >> x;
std::ios::pos_type after = source.tellg();
std::cout << before << ' ' << static_cast<int>(x) << ' '
<< after << std::endl;
return 0;
这会转储 test.dat 的内容,每行一个字节,显示文件之前和之后的位置。
果然,如果我的文件恰好有两个字节的序列 0x0D-0x0A(对应回车和换行),那些字节就被跳过了。
我以二进制模式打开了流。这不应该阻止它解释行分隔符吗? 提取运算符是否总是使用文本模式? 从二进制 istream 中逐字节读取的正确方法是什么?Windows 上的 MSVC++ 2008。
【问题讨论】:
【参考方案1】:>> 提取器用于格式化输入;他们跳过空白(通过
默认)。对于单字符无格式输入,您可以使用
istream::get()
(返回 int
,如果读取失败则返回 EOF,或者
[0,UCHAR_MAX] 范围内的值)或 istream::get(char&)
(将
在参数中读取的字符,返回转换为
bool
,读取成功则为true,失败则为false。
【讨论】:
哇,如果没有某种类型的转换,我就无法从二进制文件中读取一个字节。 这是因为流是为文本设计的(即使以二进制模式打开)。一般来说,在读取真正的二进制日期时,我会使用系统级别的例程(Unix 下的 open/read/write/close),而不是使用 iostream。 仍然可以使用 std::skipws 以便流跳过空格(和其他格式),即使与流运算符一起使用 @Ghita 我想你的意思是std::noskipws
。
抱歉,在这种情况下您不想跳过空格【参考方案2】:
有一个read() 成员函数,您可以在其中指定字节数。
【讨论】:
【参考方案3】:你为什么使用格式化提取,而不是.read()
?
【讨论】:
因为source >> x;
比source.read(reinterpret_cast<char *>(&x));
更容易阅读,而且我没想到二进制文件中单个字节的提取运算符会进行任何格式化。
对于单个字节,.get()
可能比 .read()
更有效。但无论如何,实现可能有.read
调用.get
,反之亦然。
source.read((char*)&x) 更短,在这种情况下,C 样式转换的含义与重新解释转换相同。
@cubuspl42:最好避免养成使用任何 C 风格转换的习惯,不过【参考方案4】:
source.get()
会给你一个字节。它是未格式化的输入函数。 operator>> 是格式化的输入函数,可能意味着跳过空白字符。
【讨论】:
【参考方案5】:正如其他人提到的,您应该使用istream::read()
。但是,如果您必须使用格式化提取,请考虑std::noskipws
。
【讨论】:
不,我的意思是 noskipws。 我的意思是你仍然可以使用格式化提取(使用流运算符),只是在这种情况下必须指定skipws以上是关于逐字节读取二进制 istream的主要内容,如果未能解决你的问题,请参考以下文章