正在从文件中读取位
Reading bits from file
例如,我可以使用从文件中读取4个字节
ifstream r(filename , ios::binary | ios::in)
uint_32 readHere;
r.read( (char*)&readHere, 4 )
但是我怎么能读取4.5字节=4字节和4位。
我想到的是
ifstream r(filename , ios::binary | std::in)
uint_64t readHere;
r.read( (char*)&readHere, 5 ) // reading 5 bytes ;
uint_64t tmp = readHere & 11111111 // extract 5th bytes
tmp = tmp >> 4 // get first half of the bites
readHere = (( readHere >> 8 ) << 8) | tmp // remove 5th byte then add 4 bits
但我不确定我应该如何取半个字节,如果是第一个还是最后一个4。有没有更好的方法来取回它?
无论是在文件中还是在内存中,您都可以读取或写入的最小单元是char(在通用系统中是一个字节(*))。您可以按字节浏览较长的元素,有效地说,这里的端序很重要。
uint32_t u = 0xaabbccdd;
char *p = static_cast<char *>(&u);
char c = p[0]; // c is 0xdd on a little endian system and 0xaa on a big endian one
但是,一旦你在字节内,你所能做的就是使用逐位和和移位来提取低位或高位。这里不再有endianness,除非您决定使用一个约定。
顺便说一句,如果你在网络接口上读取,甚至在单独传输位的串行线上读取,你一次只能读取一个完整的字节,并且无法在一次读取中只读取4位,在下一次读取时读取其他4位。
(*)旧的系统(80年代的CDC)过去每个字符有6位,但当时C++还不存在,我不确定那里是否存在C编译器。
目前还不清楚这是您控制的文件格式,还是其他文件格式。无论如何,让我们假设您有一些整数数据类型,可以保存36位无符号值:
typedef uint64_t u36;
现在,无论您的系统使用的是大端序还是小端序,您都可以通过一次一个字节的操作,以可预测的顺序将值写入二进制流。让我们使用big-endian,因为将比特组合在一起创建值稍微容易一些。
您可以使用简单的移位和掩蔽到一个小缓冲区中。唯一要决定的是在哪里截断半字节。但是,如果你遵循将每个值再移位8位的模式,那么余数自然会落在高位。
ostream & write_u36( ostream & s, u36 val )
{
char bytes[5] = {
(val >> 28) & 0xff,
(val >> 20) & 0xff,
(val >> 12) & 0xff,
(val >> 4 ) & 0xff,
(val << 4 ) & 0xf0
};
return s.write( bytes, 5 );
}
但这并不是你写这些数字的方式。你必须把第5个字节拖到完成,或者你可以把下一个值打包进去。或者你总是一次写两个值:
ostream & write_u36_pair( ostream & s, u36 a, u36 b )
{
char bytes[9] = {
(a >> 28) & 0xff,
(a >> 20) & 0xff,
(a >> 12) & 0xff,
(a >> 4 ) & 0xff,
(a << 4 ) & 0xf0 | (b >> 32) & 0x0f,
(b >> 24) & 0xff,
(b >> 16) & 0xff,
(b >> 8) & 0xff,
b & 0xff
};
return s.write( bytes, 9 );
}
因此,现在,您可能会看到如何读取值并将其反序列化为整数。最简单的方法是一次读两本。
istream & read_u36_pair( istream & s, u36 & a, u36 & b )
{
char bytes[9];
if( s.read( bytes, 9 ) )
{
a = (u36)bytes[0] << 28
| (u36)bytes[1] << 20
| (u36)bytes[2] << 12
| (u36)bytes[3] << 4
| (u36)bytes[4] >> 4;
b = ((u36)bytes[4] & 0x0f) << 32
| (u36)bytes[5] << 24
| (u36)bytes[6] << 16
| (u36)bytes[7] << 8
| (u36)bytes[8];
}
return s;
}
如果你想一次读取一个,你需要跟踪一些状态,这样你就知道要读取多少字节(5或4),以及要应用哪些移位操作。像这样天真的东西:
struct u36deser {
char bytes[5];
int which = 0;
};
istream & read_u36( istream & s, u36deser & state, u36 & val )
{
if( state.which == 0 && s.read( state.bytes, 5 ) )
{
val = (u36)state.bytes[0] << 28
| (u36)state.bytes[1] << 20
| (u36)state.bytes[2] << 12
| (u36)state.bytes[3] << 4
| (u36)state.bytes[4] >> 4;
state.which = 1;
}
else if( state.which == 1 && s.read( state.bytes, 4 ) )
{
val = ((u36)state.bytes[4] & 0x0f) << 32 // byte left over from previous call
| (u36)state.bytes[0] << 24
| (u36)state.bytes[1] << 16
| (u36)state.bytes[2] << 8
| (u36)state.bytes[3];
state.which = 0;
}
return s;
}
所有这些都是纯粹的假设,这似乎是你问题的重点。还有许多其他串行化位的方法,其中一些方法并不明显。
- 使用新行和不使用新行读取文件
- 读取文件并输入到矢量中
- 读取文件的最后一行并输入到链接列表时出错
- 为什么在读取文件大小时文件IO速度会发生变化
- 读取文件时运行时的未知行为
- 如何逐行读取文件,每行中的内容都用空格分隔并将其写入新文件中
- 读取文件中所有可能的十六进制 16 字节序列并打印每个序列
- C++ 读取文件读取文件不正确
- 读取文件并将其存储在unordered_map中时出现问题
- 读取文件时无法使用 OpenMP 获得加速
- 使用istringstearm和get行缓慢读取文件
- 如何继续读取不同功能中的文件,而不是从头开始再次读取文件?
- 读取文件时引发异常
- 从标准输入读取文件后读取用户输入
- 在读取文件后重置句柄
- 如何在C++编译时读取文件?
- std::ifstream 在读取文件中最后一项时设置 eofbit,但仅在读取数值类型时发生
- 读取文件在第二次调用时返回INVALID_HANDLE
- 通过指针读取文件
- 逐行读取文件,并将数据插入变量和数组中