C ++将bitset写入二进制文件

时间:2012-09-07 04:27:40

标签: c++ c bit-manipulation binaryfiles

希望有人可以提供帮助。我的问题如下:

我正在创建包含二进制数据的文件。在每个文件的开头是二进制标题,其具有关于文件内容的信息。文件头是固定大小,52个字节。标头在标头内的特定字节偏移处具有特定的信息,但是一些信息仅覆盖一个字节的部分,比如3比特。

例如:

  

字节1-4 =文件长度

     

字节5-8 =标题长度

     

字节8-9 =版本信息

     

字节10-13 =文件创建时间戳

     
    

位1-4 =月(1-12)

         

第5-9位=第(1-31)天

         

位10-14 =小时(0-23)

         

位15-20 =分钟(0-59)

         

位21 = UTC偏移方向

         

第22-26位= UTC偏移小时

         

位27-32 = UTC偏移分钟

  
     

等...

某些值是静态定义的,有些是在运行时确定的。我试图做的是创建标题的“映射”,定义属性必须消耗的位数,以及由位表示的值。它们存储在int对的向量中,int_pair.first是值,int_pair.second是位数。然后我将提供的值(所有整数)转换为二进制格式,并将二进制表示法插入到字符串流中。然后我从二进制值的字符串表示创建一个bitset,并将其写入文件。我的问题是字节没有以正确的顺序显示在输出文件中。

我将省略获取值的方法,并在我的示例中仅提供整数,为简洁起见,我将截断标题中的一些信息(因此在此示例中标题为14个字节,而不是52个),但这里大致是我正在做的事情:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <bitset>
#include <vector>
#include <algorithm>

int main ()
{
    vector<pair<int,int>> header_vec;

    header_vec.push_back(make_pair(9882719,32)); // file length
    header_vec.push_back(make_pair(52,32)); // header length
    header_vec.push_back(make_pair(6,3)); // high release identifier
    header_vec.push_back(make_pair(4,5)); // high version identifier
    header_vec.push_back(make_pair(6,3)); // low release identifier
    header_vec.push_back(make_pair(4,5)); // low version identifier

    // file open timestamp
    header_vec.push_back(make_pair(9,4));  // month
    header_vec.push_back(make_pair(6,5));  // day
    header_vec.push_back(make_pair(19,5)); // hour
    header_vec.push_back(make_pair(47,6)); // min
    header_vec.push_back(make_pair(0,1));  // utc direction
    header_vec.push_back(make_pair(0,5));  // utc offset hours
    header_vec.push_back(make_pair(0,6));  // utc offset minutes

    ostringstream oss;

    // convert each integer to binary representation
    for ( auto i : header_vec )
    {
        for (unsigned int j(i.second-1); j != -1; --j)
        {
            oss << ((i.first &(1 << j)) ? 1 : 0);
        }
    }

    // copy oss
    string str = oss.str();

    // create bitset
    bitset<112> header_bits(string(str.c_str()));

    // write bitset to file
    ofstream output("header.out", ios::out | ios::binary );
    output.write( reinterpret_cast<char *>(&header_bits), 14);
    output.close();

    return 0;

}

现在,在大多数情况下,这种方法似乎有效,除了这些位是相反的。如果我查看fm中的输出文件,我希望看到这个:

File: header.out    (0x0e bytes)
Byte: 0x0

00    00 96 cc 5f 00 00 00 34 c4 c4 93 4e f0 00           ..._...4...N...O

      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f      0123456789abcdef

事实上,我看到了这一点:

File: header.out    (0x0e bytes)
Byte: 0x0

00    00 f0 4e 93 c4 c4 34 00 00 00 5f cc 96 00           @O...N...4..._..

      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f      0123456789abcdef

我尝试在创建bitset之前反转str,但这也不会产生所需的输出。

我想我不太了解bitset,以了解为什么会发生这种情况。任何和所有输入都非常感谢!另外,如果有不同的方法来实现这一点,请分享!

提前致谢... -J

2 个答案:

答案 0 :(得分:1)

bitset<>直接写为内存转储肯定是不可移植的,正如需要reinterpret_cast<>所示。换句话说,即使数据是在一个很好的块中布局,你也不知道是怎么做的。

如果我是你,我会编写一个dumber函数来从bitset中提取8位的块,并使用普通访问运算符[]将它们作为字节写入文件。

至于另一种方法,当我想读/写二进制文件时,我通常会做的是定义一个直接映射到文件布局的结构或结构集。

例如:

struct Timestamp
{
    int month:4;
    int day:5;
    int hour:5;
    int minute:6;
    int utcOffsetDirection:1;
    int utcOffsetHour:5;
    int utcOffsetMinute:5;

};

答案 1 :(得分:1)

为什么你不使用struct bitfield,所以你只需要读取和写入结构,而不必担心“位解析”。关注内存对齐。确保添加一些填充以适合单词bondaries

struct timestamp{
       unsigned mont:4;
       unsigned day:5;
       unsigned hour:5;
       unsigned minute:6;
       unsigned utc:1;
       unsigned utc_hour:5;
       unsigned utc_min:6   
};


struct header{
   int32_t file_length;
   int32_t header_lenght;
   int16_t version;
   timestamp tmsp;
};