Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何从二进制文件中读取位整数数据?_C++ - Fatal编程技术网

C++ 如何从二进制文件中读取位整数数据?

C++ 如何从二进制文件中读取位整数数据?,c++,C++,我有一个由硬件生成的数据文件。有些数据是4位宽,有些是12位宽。Matlab能够使用fread(fp,1,'ubit4=>uint16')处理这些数据。我试着用C++来做,但是似乎没有简单的方法。我可以按字节/int/long/long-long进行读取,然后提取出请求的位。但处理数百兆字节的数据似乎效率低下 要概括这个问题,问题是如何读取位N整数(例如N从1到64)?有人能推荐一种从C++中读取这种数据的好方法吗? < p>你的问题不是很具体,所以我只能推荐一些一般的想法。 您可能希望以块的形

我有一个由硬件生成的数据文件。有些数据是4位宽,有些是12位宽。Matlab能够使用fread(fp,1,'ubit4=>uint16')处理这些数据。我试着用C++来做,但是似乎没有简单的方法。我可以按字节/int/long/long-long进行读取,然后提取出请求的位。但处理数百兆字节的数据似乎效率低下


要概括这个问题,问题是如何读取位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