C++ 如何从二进制文件中读取位整数数据?
我有一个由硬件生成的数据文件。有些数据是4位宽,有些是12位宽。Matlab能够使用fread(fp,1,'ubit4=>uint16')处理这些数据。我试着用C++来做,但是似乎没有简单的方法。我可以按字节/int/long/long-long进行读取,然后提取出请求的位。但处理数百兆字节的数据似乎效率低下C++ 如何从二进制文件中读取位整数数据?,c++,C++,我有一个由硬件生成的数据文件。有些数据是4位宽,有些是12位宽。Matlab能够使用fread(fp,1,'ubit4=>uint16')处理这些数据。我试着用C++来做,但是似乎没有简单的方法。我可以按字节/int/long/long-long进行读取,然后提取出请求的位。但处理数百兆字节的数据似乎效率低下 要概括这个问题,问题是如何读取位N整数(例如N从1到64)?有人能推荐一种从C++中读取这种数据的好方法吗? < p>你的问题不是很具体,所以我只能推荐一些一般的想法。 您可能希望以块的形
要概括这个问题,问题是如何读取位N整数(例如N从1到64)?有人能推荐一种从C++中读取这种数据的好方法吗? < p>你的问题不是很具体,所以我只能推荐一些一般的想法。 您可能希望以块的形式读取文件,例如一次读取4096字节(这是典型的页面大小)——但较大的块也可以(甚至可能是64kiB或512kiB,只是实验而已)。一旦读到块,就从内存中处理它 为了正确起见,我们应该将块内存生成为目标整数的数组。例如,对于4字节整数,我们可以这样做:
#include <cstdint>
#include <memory>
#include <cstdio>
uint32_t buf[1024];
typedef std::unique_ptr<std::FILE, int (*)(std::FILE *)> unique_file_ptr;
static unique_file_ptr make_file(const char * filename, const char * flags)
{
std::FILE * const fp = std::fopen(filename, flags);
return unique_file_ptr(fp ? fp : nullptr, std::fclose);
}
int main()
{
auto fp = make_file("thedata.bin", "rb");
if (!fp) return 1;
while (true)
{
if (4096 != std::fread(reinterpret_cast<char*>(buf), 4096, fp.get())) break;
// process buf[0] up to buf[1023]
}
}
#包括
#包括
#包括
uint32_t buf[1024];
typedef std::unique_ptr unique_file_ptr;
静态唯一_文件_ptr生成_文件(常量字符*文件名,常量字符*标志)
{
std::FILE*const fp=std::fopen(文件名、标志);
返回唯一的_文件_ptr(fp?fp:nullptr,std::fclose);
}
int main()
{
自动fp=生成文件(“thedata.bin”、“rb”);
如果(!fp)返回1;
while(true)
{
如果(4096!=std::fread(reinterpret_cast(buf),4096,fp.get())中断;
//处理buf[0]到buf[1023]
}
}
出于性能原因,我选择了C库<代码> fOpen< /COD>/<代码> FRADE< /COD>超过C++的IOSROWS;我不能说这个决定是基于个人经验。(如果你有一个旧的编译器,你可能需要头
,也许你没有unique\u ptr
,在这种情况下你可以手动使用std::FILE*
和std::fopen
)
除了全局buf
,您还可以制作一个std::vector
,将其调整到足够大的大小,并直接读入其数据缓冲区(&buf[0]
或buf.data()
)
如果需要读取长度不是2、4、8或16字节的整数,则必须读入字符数组,并通过代数运算(例如buf[pos]+(buf[pos+1]#include)手动提取数字
#包括
#包括
#包括
类位缓冲区{
字符缓冲区;
字符保持位;
公众:
bitbuffer():保留位(0),缓冲区(0){
无符号长-长读取(无符号字符位){
无符号长结果=0;
//如果缓冲区没有容纳足够的位
while(位>保持位){
//抓取缓冲区中的所有位
位-=保持位;
结果|=((无符号长)缓冲区)>(保持位-位);
//从缓冲区中删除这些位
保持位-=位;
buffer&=(1ull在我的项目中,我有从流中读取N位的相同要求
源代码可在以下位置获得:
或者,您可以从下载整个软件包及其文档,并仅使用基类。
它是开源的(FreeBSD)并且经过测试。除了STL,不需要其他库
基本上,您创建一个流,然后将streamReader连接到该流。
流读取器能够读取字节块或请求的比特量。几个流读取器对象可以连接到同一个流
这些类当前用于读取jpeg文件或医学图像文件
适用于多种操作系统(包括iOS)、大型和低端计算机
例如:
#include "../../library/imebra/include/imebra.h"
// Open the file containing the dicom dataset
ptr<puntoexe::stream> inputStream(new puntoexe::stream);
inputStream->openFile(argv[1], std::ios_base::in);
// Connect a stream reader to the dicom stream. Several stream reader
// can share the same stream
ptr<puntoexe::streamReader> reader(new streamReader(inputStream));
#include“../../library/imebra/include/imebra.h”
//打开包含dicom数据集的文件
ptr输入流(新的puntoexe::流);
inputStream->openFile(argv[1],std::ios\u base::in);
//将流读取器连接到dicom流。多个流读取器
//可以共享同一个流
ptr读卡器(新streamReader(inputStream));
下面是一个如何从变量中获取位范围的示例
该示例模拟从文件中读取一些二进制数据并将其存储在向量中
将数据从向量复制(提取函数模板)到变量中。之后,get_bits函数将请求的位返回到新变量中。就这么简单
#include <vector>
using namespace std;
template<typename T>
T extract(const vector<unsigned char> &v, int pos)
{
T value;
memcpy(&value, &v[pos], sizeof(T));
return value;
}
template<typename IN, typename OUT>
OUT get_bits(IN value, int first_bit, int last_bit)
{
value = (value >> first_bit);
double the_mask = pow(2.0,(1 + last_bit - first_bit)) - 1;
OUT result = value & static_cast<IN>(the_mask);
return result;
}
int main()
{
vector<unsigned char> v;
//Simulate that we have read a binary file.
//Add some binary data to v.
v.push_back(255);
v.push_back(1);
//0x01 0xff
short a = extract<short>(v,0);
//Now get the bits from the extracted variable.
char b = get_bits<short,char>(a,8,8);
short c = get_bits<short,short>(a,2,5);
int d = get_bits<short,int>(a,0,7);
return 0;
}
#包括
使用名称空间std;
样板
T提取(常量向量和v,整数位置)
{
T值;
memcpy(&value,&v[pos],sizeof(T));
返回值;
}
样板
OUT get_位(值内、int first_位、int last_位)
{
值=(值>>第一位);
将_掩码加倍=pow(2.0,(1+最后一个_位-第一个_位))-1;
输出结果=值和静态施法(屏蔽);
返回结果;
}
int main()
{
向量v;
//模拟我们已经读取了一个二进制文件。
//向v添加一些二进制数据。
v、 推回(255);
v、 推回(1);
//0x01 0xff
短a=提取(v,0);
//现在从提取的变量中获取位。
char b=获取位(a,8,8);
短c=获取_位(a,2,5);
int d=获取位(a,0,7);
返回0;
}
这只是一个没有任何错误检查的简单示例
您可以使用extract函数模板从向量中的任何位置获取数据。此向量只有2个元素,短字符的大小为2字节,因此extract函数的pos参数为0
祝你好运!谢谢大家提供的答案,它们都非常有帮助。我不想回答我的问题并获得学分,但我觉得我有义务就这个问题的进展给出反馈。所有学分都归于上述答案
为了实现matlab fread读取位整数的类似功能,我觉得模板类不合适,所以我提出了几个函数来处理Nope,您必须编写一个自定义函数/类来处理读取部分字节
#include <vector>
using namespace std;
template<typename T>
T extract(const vector<unsigned char> &v, int pos)
{
T value;
memcpy(&value, &v[pos], sizeof(T));
return value;
}
template<typename IN, typename OUT>
OUT get_bits(IN value, int first_bit, int last_bit)
{
value = (value >> first_bit);
double the_mask = pow(2.0,(1 + last_bit - first_bit)) - 1;
OUT result = value & static_cast<IN>(the_mask);
return result;
}
int main()
{
vector<unsigned char> v;
//Simulate that we have read a binary file.
//Add some binary data to v.
v.push_back(255);
v.push_back(1);
//0x01 0xff
short a = extract<short>(v,0);
//Now get the bits from the extracted variable.
char b = get_bits<short,char>(a,8,8);
short c = get_bits<short,short>(a,2,5);
int d = get_bits<short,int>(a,0,7);
return 0;
}
#include <math.h>
#include <memory.h>
typedef unsigned _int8 _uint8;
typedef unsigned _int16 _uint16;
typedef unsigned _int32 _uint32;
typedef unsigned _int64 _uint64;
class bitbuffer
{
_uint8 *pbuf;
_uint8 *pelem; //can be casted to int16/32/64
_uint32 pbuf_len; //buf length in byte
_uint32 pelem_len; //element length in byte
union membuf
{
_uint64 buf64;
_uint32 buf32;
_uint16 buf16;
_uint8 buf8[2];
} tbuf;
//bookkeeping information
_uint8 start_bit; //
_uint32 byte_pos; //current byte position
_uint32 elem_pos;
public:
bitbuffer(_uint8 *src,_uint32 src_len,_uint8 *dst,_uint32 dst_len)
{
pbuf=src;pelem=dst;
pbuf_len=src_len;pelem_len=dst_len;
start_bit=0;byte_pos=0;elem_pos=0;
} //to define the source and destination
void set_startbit(_uint8 bit) {start_bit=bit;}
void set_bytepos(_uint32 pos) {byte_pos=pos;}
void set_elempos(_uint32 pos) {elem_pos=pos;}
void reset() {start_bit=0;byte_pos=0;elem_pos=0;} //for restart something from somewhere else
//OUT getbits(IN a, _uint8 nbits); //get nbits from a using start and byte_pos
_uint32 get_elem_uint8(_uint32 num_elem,_uint8 nbits) //output limit to 8/16/32/64 only
{
_uint32 num_read=0;
_uint16 mask=pow(2,nbits)-1;//00000111 for example nbit=3
while(byte_pos<=pbuf_len-2)
{
//memcpy((char*)&tbuf.buf16,pbuf+byte_pos,2); //copy 2 bytes into our buffer, this may introduce redundant copy
tbuf.buf8[1]=pbuf[byte_pos]; //for little endian machine, swap the bytes
tbuf.buf8[0]=pbuf[byte_pos+1];
//now we have start_bits, byte_pos, elem_pos, just finish them all
while(start_bit<=16-nbits)
{
pelem[elem_pos++]=(tbuf.buf16>>(16-start_bit-nbits))&mask;//(tbuf.buf16&(mask<<(16-start_bit))
start_bit+=nbits; //advance by nbits
num_read++;
if(num_read>=num_elem)
{
break;
}
}
//need update the start_bit and byte_pos
byte_pos+=(start_bit/8);
start_bit%=8;
if(num_read>=num_elem)
{
break;
}
}
return num_read;
}
/*
_uint32 get_elem_uint16(_uint32 num_elem,_uint8 nbits) //output limit to 8/16/32/64 only
{
_uint32 num_read=0;
_uint32 mask=pow(2,nbits)-1;//00000111 for example nbit=3
while(byte_pos<pbuf_len-4)
{
memcpy((char*)&tbuf.buf32,pbuf+byte_pos,4); //copy 2 bytes into our buffer, this may introduce redundant copy
//now we have start_bits, byte_pos, elem_pos, just finish them all
while(start_bit<=32-nbits)
{
pelem[elem_pos++]=(tbuf.buf32>>(32-start_bit-nbits))&mask;//(tbuf.buf16&(mask<<(16-start_bit))
start_bit+=nbits; //advance by nbits
num_read++;
if(num_read>=num_elem)
{
break;
}
}
//need update the start_bit and byte_pos
start_bit%=8;
byte_pos+=(start_bit/8);
if(num_read>=num_elem)
{
break;
}
}
return num_read;
}
_uint32 get_elem_uint32(_uint32 num_elem,_uint8 nbits) //output limit to 8/16/32/64 only
{
_uint32 num_read=0;
_uint64 mask=pow(2,nbits)-1;//00000111 for example nbit=3
while(byte_pos<pbuf_len-8)
{
memcpy((char*)&tbuf.buf16,pbuf+byte_pos,8); //copy 2 bytes into our buffer, this may introduce redundant copy
//now we have start_bits, byte_pos, elem_pos, just finish them all
while(start_bit<=64-nbits)
{
pelem[elem_pos++]=(tbuf.buf64>>(64-start_bit-nbits))&mask;//(tbuf.buf16&(mask<<(16-start_bit))
start_bit+=nbits; //advance by nbits
num_read++;
if(num_read>=num_elem)
{
break;
}
}
//need update the start_bit and byte_pos
start_bit%=8;
byte_pos+=(start_bit/8);
if(num_read>=num_elem)
{
break;
}
}
return num_read;
}
//not work well for 64 bit!
_uint64 get_elem_uint64(_uint32 num_elem,_uint8 nbits) //output limit to 8/16/32/64 only
{
_uint32 num_read=0;
_uint64 mask=pow(2,nbits)-1;//00000111 for example nbit=3
while(byte_pos<pbuf_len-2)
{
memcpy((char*)&tbuf.buf16,pbuf+byte_pos,8); //copy 2 bytes into our buffer, this may introduce redundant copy
//now we have start_bits, byte_pos, elem_pos, just finish them all
while(start_bit<=16-nbits)
{
pelem[elem_pos++]=(tbuf.buf16>>(16-start_bit-nbits))&mask;//(tbuf.buf16&(mask<<(16-start_bit))
start_bit+=nbits; //advance by nbits
num_read++;
if(num_read>=num_elem)
{
break;
}
}
//need update the start_bit and byte_pos
start_bit%=8;
byte_pos+=(start_bit/8);
if(num_read>=num_elem)
{
break;
}
}
return num_read;
}*/
};
#include <iostream>
using namespace std;
int main()
{
_uint8 *pbuf=new _uint8[10];
_uint8 *pelem=new _uint8[80];
for(int i=0;i<10;i++) pbuf[i]=i*11+11;
bitbuffer vbit(pbuf,10,pelem,10);
cout.setf(ios_base::hex,ios_base::basefield);
cout<<"Bytes: ";
for(i=0;i<10;i++) cout<<pbuf[i]<<" ";
cout<<endl;
cout<<"1 bit: ";
int num_read=vbit.get_elem_uint8(80,1);
for(i=0;i<num_read;i++) cout<<(int)pelem[i];
cout<<endl;
vbit.reset();
cout<<"2 bit: ";
num_read=vbit.get_elem_uint8(40,2);
for(i=0;i<num_read;i++) cout<<(int)pelem[i]<<" ";
cout<<endl;
vbit.reset();
cout<<"3 bit: ";
num_read=vbit.get_elem_uint8(26,3);
for(i=0;i<num_read;i++) cout<<(int)pelem[i]<<' ';
cout<<endl;
vbit.reset();
cout<<"4 bit: ";
num_read=vbit.get_elem_uint8(20,4);//get 10 bit-12 integers
for(i=0;i<num_read;i++) cout<<(int)pelem[i]<<" ";
cout<<endl;
vbit.reset();
cout<<"5 bit: ";
num_read=vbit.get_elem_uint8(16,5);//get 10 bit-12 integers
for(i=0;i<num_read;i++) cout<<(int)pelem[i]<<" ";
cout<<endl;
vbit.reset();
cout<<"6 bit: ";
num_read=vbit.get_elem_uint8(13,6);//get 10 bit-12 integers
for(i=0;i<num_read;i++) cout<<(int)pelem[i]<<" ";
cout<<endl;
vbit.reset();
cout<<"7 bit: ";
num_read=vbit.get_elem_uint8(11,7);//get 10 bit-12 integers
for(i=0;i<num_read;i++) cout<<(int)pelem[i]<<" ";
cout<<endl;
vbit.reset();
cout<<"8 bit: ";
num_read=vbit.get_elem_uint8(10,8);//get 10 bit-12 integers
for(i=0;i<num_read;i++) cout<<(int)pelem[i]<<" ";
cout<<endl;
vbit.reset();
return 0;
}
Bytes: b 16 21 2c 37 42 4d 58 63 6e
1 bit: 0000101100010110001000010010110000110111010000100100110101011000011000110
1101110
2 bit: 0 0 2 3 0 1 1 2 0 2 0 1 0 2 3 0 0 3 1 3 1 0 0 2 1 0 3 1 1 1 2 0 1 2 0 3 1
2 3 2
3 bit: 0 2 6 1 3 0 4 1 1 3 0 3 3 5 0 2 2 3 2 5 4 1 4 3
4 bit: 0 b 1 6 2 1 2 c 3 7 4 2 4 d 5 8 6 3 6 e
5 bit: 1 c b 2 2 b 1 17 8 9 6 15 10 18 1b e
6 bit: 2 31 18 21 b 3 1d 2 13 15 21 23
7 bit: 5 45 44 12 61 5d 4 4d 2c 18 6d
8 bit: b 16 21 2c 37 42 4d 58 63 6e
Press any key to continue