【问题标题】:Read a binary file where every element is a 2 byte integer读取一个二进制文件,其中每个元素都是一个 2 字节整数
【发布时间】:2019-01-08 19:46:38
【问题描述】:

我有一个扩展名为 .b16 的二进制文件,包含的信息为无符号整数(范围 0..65535,文件扩展名 .b16,字节顺序:低字节/高字节)。

主要文件是 otypes03.b08 到 otypes08.b08、otypes09.b16 和 otypes10.b16。它们包含所有不等价的坐标 给定点数 n 的点集(订单类型)。

我已成功读取所有扩展名为 .b08 的文件,但是在读取 .b16 文件时,我没有得到预期的信息。

到目前为止我所拥有的:(这是读取算法的修改版本,专门用于 .b16 格式)

int readPoints(int n, string file_name, vector<Point> & vPoints){
    ifstream input(file_name, std::ios::binary);
    if(input.fail()) return 1;

    vector< unsigned char> buffer(std::istreambuf_iterator<char>(input), {});
    //Copying each pair of binary points to a vector of Point objects
    Point temp;
    for( unsigned int i=0;i< buffer.size();i+=4){
        temp.x = buffer[i] | buffer[i+1]  ;
        temp.y = buffer[i+2] | buffer[i+3]  ;
        vPoints.push_back(temp);
    }
    return 0;
}

文件的每个元素都是平面中一个点的坐标,但是我似乎读错了,读取的坐标不是应该的。我不知道我做错了什么。

我用于 .b08 格式的内容:

//Reads a file of binary points and stores it on vector vPoints.
int readPoints(int n, string file_name, vector<Point> & vPoints){
    ifstream input(file_name, std::ios::binary);
    if(input.fail()) return 1;
    // copies all data into buffer
    //Stored as unsigned int. Arithmetic operations (+-*/) can be used! :)
    //Can be treated as signed int or unsigned int.
    vector< unsigned char> buffer(std::istreambuf_iterator<char>(input), {});
    //Copying each pair of binary points to a vector of Point objects
    Point temp;
    cout << "Buffer size: " << buffer.size() << endl;
    for( unsigned int i=0;i< buffer.size();i+=2){
        temp.x = buffer[i];
        temp.y = buffer[i+2];
        vPoints.push_back(temp);
    }
    return 0;
}

关于我正在使用的数据库的更多信息在这里: http://www.ist.tugraz.at/aichholzer/research/rp/triangulations/ordertypes/

我要读取的文件是 otypes09.b16,大小为 5.7MB,以防您想尝试一下。

感谢您的宝贵时间。

【问题讨论】:

  • 您有两种选择: 1) 将 16 位文件读入内存,然后根据需要交换字节;或 2) 一次读取两个字节,组装成正确的字节序并存储到内存中。
  • 字节顺序是否可能与您的系统不同?如果是这样,您应该在读取文件时交换字节顺序
  • 顺便说一句,如果文件的字节顺序与您的系统相同,则以16位读取数据,无需转换。

标签: c++ binaryfiles binary-data


【解决方案1】:
for( unsigned int i=0;i< buffer.size();i+=4){
    temp.x = buffer[i] | buffer[i+1]  ;
    temp.y = buffer[i+2] | buffer[i+3]  ;
    vPoints.push_back(temp);
}

以上内容不正确 - 您将高 8 位的位与低 8 位顶部的位进行或运算,这会破坏数据。您需要先移动位(需要移动哪些位取决于文件是以大端格式还是小端格式存储其 16 位字)。

如果文件的数据是 little-endian 格式,这应该可以:

// read in little-endian 16-bit words
for( unsigned int i=0;i< buffer.size();i+=4){
    temp.x = ((unsigned short)buffer[i+0]) | (((unsigned short)buffer[i+1])<<8);
    temp.y = ((unsigned short)buffer[i+2]) | (((unsigned short)buffer[i+3])<<8);
    vPoints.push_back(temp);
}

...或者如果文件的数据以大端格式存储,它会更像这样:

// read in big-endian 16-bit words
for( unsigned int i=0;i< buffer.size();i+=4){
    temp.x = (((unsigned short)buffer[i+0])<<8) | ((unsigned short)buffer[i+1]);
    temp.y = (((unsigned short)buffer[i+2])<<8) | ((unsigned short)buffer[i+3]);
    vPoints.push_back(temp);
}

【讨论】:

  • 问题末尾的括号表明该文件是 little-endian,因此通过将其放在首位来强调 little-endian 的情况可能会更清楚。
  • 这行得通,但是,我得到的值非常大,我不知道这是否可以,或者在处理它们时是否必须再次移回 8 位。显示的值实际上对于每种订单类型都有正确的形状,只是它们太大了,这让我怀疑。感谢您的宝贵时间。
  • 无符号 16 位整数可以保存 0-65535 之间的值;这样它们就不同于只能保存 0-255 值的无符号 8 位整数。我怀疑较大的值是预期的行为(因为能够保持较大的值是使用 16 位而不是 8 位编码的唯一优势,否则,为什么要浪费磁盘空间使文件大两倍?)跨度>
  • 只需要对这些数据进行我尝试的操作是有意义的,谢谢!将此答案标记为最终答案。
【解决方案2】:

这是一种方法:

uint8_t lsb;
uint8_t msb;
uint16_t value;
std::vector<uint16_t> database;
//...
input.read((char *) &lsb, sizeof(lsb));
input.read((char *) &msb, sizeof(msb));
value = msb * 256 + lsb;
database.push_back(value);

因为这是一个二进制文件,所以使用read方法。 您可以将 value 分配替换为:
value = msb &lt;&lt; 8 | lsb;
虽然一个好的编译器应该将第一个 value 赋值转换为第二个。

【讨论】:

    【解决方案3】:

    在这种情况下,取决于数据的平均值,并且具有绝对分辨率,我喜欢使用联合。你可以做的是有一个联合,它有一个 int 成员以及一个包含 2 个短裤的结构。每个 short 将保存 2 个 16 位整数的二进制结构。

    话虽如此,以上答案可能对您来说还不错。这样的做法很多,所以为你设计合适的api吧!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 2017-04-14
      • 2022-10-02
      相关资源
      最近更新 更多