【问题标题】:How do I read the whole 64 bytes of a binary file?如何读取二进制文件的全部 64 个字节?
【发布时间】:2017-08-15 19:00:48
【问题描述】:

我正在编写一个小程序,它以二进制形式读取磁盘映像文件,然后检查其分区条目表以显示每个分区、它的类型、起始扇区和大小。

到目前为止,它准确地读取了前 16 个字节,但其余的分区条目无法识别或出现某种错误。 结果如下所示: 编辑:输出的第一行应该是这样的:

 `Partition 0: Type: FAT-16 Start: 63 Size: 518760`

我错过了什么?如何修复代码以使所有分区条目都给出适当的结果?

using namespace std;
#include <iostream>
#include <fstream>

struct Partition { char type; int start_sect; int size; } part_entry[4];  // 4 x partition table entry 


int main(int argc, char *argv[])
{
//DECLARATIONS
int i, offset = 26, not_exist = 0;
char buf_part_table[64], vol_type[12];
char* diskdata;
int n;
streampos begin, end;


ifstream diskimage;
diskimage.open("Sample_1.dd", ios::in | ios::binary | ios::out);


diskdata = new char[begin];
begin = diskimage.tellg();
diskdata = new char[begin];
diskimage.seekg(446, ios::beg);

diskimage.read(buf_part_table, 64);


for (i = 0; i < 4; i++)
{
    part_entry[i].type = *(char*)(buf_part_table + 0x04 + (i * offset));

    if (part_entry[i].type == 0) not_exist++;

    part_entry[i].start_sect = *(int*)(buf_part_table + 0x08 + (i * offset));

    part_entry[i].size = *(int*)(buf_part_table + 0x0C + (i * offset));

    switch (part_entry[i].type)
    {
    case 00:  strcpy(vol_type, "NOT-VALID");
        break;
    case 06:  strcpy(vol_type, "FAT-16");
        break;
    case 07:  strcpy(vol_type, "NTFS");
        break;
    case 0x0B:  strcpy(vol_type, "FAT-32");
        break;
    default:    strcpy(vol_type, "NOT-DECODED");
        break;
    }

    cout << "Partition " << i << ":" << " Type:" << vol_type << " Start: " << part_entry[i].start_sect << " Size: " << part_entry[i].size << endl;

}

return 0;
}

【问题讨论】:

  • 请不要发布文本图像(尤其是链接),而是将实际文本作为文本复制粘贴到问题的正文中。如果您有意外的输出,它也有助于查看预期输出,而不仅仅是实际输出。
  • buf_part_table + 0xXX + (i * offset)i == 3 远不是 64 个字节。可能是 offset 应该是 16,而不是 26?
  • 它如何为您编译,因为它缺少 #include &lt;cstring&gt;
  • struct Partition 将包含填充,这是否与数据的布局相匹配? (int*) 强制转换是未定义的行为(可能不满足对齐要求),请改用 memcpy。

标签: c++ binary partitioning disk istream


【解决方案1】:

您不必要地使程序不可读且难以调试。 您可以一次读取整个引导扇区,然后显示所需的内容。 这是我的快速示例(它不检查文件是否存在,有些人可能会抱怨它应该对某些字段使用 memcpy 等)

#include <iostream>
#include <fstream>
#include <cstdint>
#include <cstddef>
#include <iomanip>

using namespace std;

struct partition_t {
    uint8_t  status;
    uint8_t  start_CHS[3];
    uint8_t  type;
    uint8_t  end_CHS[3];
    uint32_t start_LBA;
    uint32_t size_LBA;
} __attribute__((packed));

struct mbr_t
{
    uint8_t     bootstrap[446];
    partition_t partitions[4];
    uint16_t    signature;
} __attribute__((packed));

int main(int argc, char *argv[])
{
    mbr_t mbr;
    ifstream diskimage;
    diskimage.open( "/tmp/mbr.dd", ios::in | ios::binary );
    diskimage.read( reinterpret_cast<char*>(&mbr), sizeof(mbr) );
    diskimage.close();

    for( int idx = 0 ; idx < 4 ; idx++ )
    {
      string bootable = (mbr.partitions[idx].status == 128) ? "yes" : "no";
      cout << " bootable : " <<  setw(5) << bootable << 
              " type : " << setw(5) << (int)mbr.partitions[idx].type << 
              " start LBA : " << setw(10) << mbr.partitions[idx].start_LBA << 
              " size : " << setw(10) << mbr.partitions[idx].size_LBA << endl;
    }

    return 0;
}

它更容易阅读,对吧?

【讨论】:

  • 实际上阅读起来并不容易,我看到它会显示我需要的信息但不是我需要的格式,我应该将类型从 int 关联到 int 对应的字符串一组预定义的类型,即FAT-16, FAT-32, NTFS,
  • 这是示例 - 将分区类型等新功能添加到字符串非常简单。主要目标是减少晦涩的读取和指针运算。
  • __attribute__((packed)); 什么是“打包”,它显示为未定义。 setw(5) &lt;&lt; 这表示没有运算符“
  • bootable : no type : 63 start LBA : 3621847040 size : 7 bootable : no type : 63 start LBA : 2956984328 size : 15 ` bootable : no type : 63 start LBA : 2740387864 size : 5` bootable : no type : 0 start LBA : 0 size : 2857697280 这是代码的输出。
  • 需要用GCC或者clang编译。 __attribute__((packed)) 防止编译器填充数据以保持默认对齐。 setw(5) 是流格式(设置宽度为 5)。你用什么编译器?
猜你喜欢
  • 2013-12-06
  • 1970-01-01
  • 2012-07-11
  • 2011-08-30
  • 2010-11-05
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多