C++读取二进制文件并转换为十六进制

8

我遇到了一些读取二进制文件并将其字节转换为十六进制表示的问题。

到目前为止,我尝试过以下方法:

ifstream::pos_type size;
char * memblock;

ifstream file (toread, ios::in|ios::binary|ios::ate);
  if (file.is_open())
  {
    size = file.tellg();
    memblock = new char [size];
    file.seekg (0, ios::beg);
    file.read (memblock, size);
    file.close();

    cout << "the complete file content is in memory" << endl;

std::string tohexed = ToHex(memblock, true);


    std::cout << tohexed << std::endl;

   }

转换为十六进制:

string ToHex(const string& s, bool upper_case)
{
    ostringstream ret;

    for (string::size_type i = 0; i < s.length(); ++i)
        ret << std::hex << std::setfill('0') << std::setw(2) << (upper_case ? std::uppercase : std::nouppercase) << (int)s[i];

    return ret.str();
}

结果: 53514C69746520666F726D61742033

当我用十六进制编辑器打开原始文件时,它显示的内容如下:

53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00
04 00 01 01 00 40 20 20 00 00 05 A3 00 00 00 47
00 00 00 2E 00 00 00 3B 00 00 00 04 00 00 00 01
00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 A3
00 2D E2 1E 0D 03 FC 00 06 01 80 00 03 6C 03 D3

有没有办法用C++获得相同的期望输出?

有效解决方案 (由Rob提供):

...

std::string tohexed = ToHex(std::string(memblock, size), true);

...
string ToHex(const string& s, bool upper_case)
{
    ostringstream ret;

    for (string::size_type i = 0; i < s.length(); ++i)
    {
        int z = s[i]&0xff;
        ret << std::hex << std::setfill('0') << std::setw(2) << (upper_case ? std::uppercase : std::nouppercase) << z;
    }

    return ret.str();
}

"memblock仅包含前15个字节,在空字节处停止(第16个)"。你为什么这么说?我没有看到你打印出memblock的内容。我怀疑memblock包含整个文件,但是你没有展示给我们的代码误解了它的内容。请将程序缩小到最小的完整程序,以演示错误,并在问题中发布该程序。http://sscce.org - Robᵩ
假设这是一项作业或某种学习任务,以下是一些提示:(1)你缺少一个while循环,(2)在刚打开流时调用tellg()是过早的。 - Sergey Kalinichenko
@develroot - 不好意思,请告诉我们您是如何得出它只包含前15个字节的结论的。 - Robᵩ
你是否检查过 size 的值不是15个字节,而只是纯巧合地在第一个空字节之前的计数?二进制模式下的 ifstream 不应该对空字节做任何处理... - Matthew Walton
@develroot - 这并不是整个程序,但足以找到错误。阅读http://sscce.org,了解我为什么要求您提供完整的程序。 - Robᵩ
显示剩余4条评论
1个回答

8
char *memblock;
… 
std::string tohexed = ToHex(memblock, true);
…

string ToHex(const string& s, bool upper_case)

问题就在这里。构造函数std::string::string(const char*)将其输入解释为以空字符结尾的字符串。因此,只有在'\0'字符之前的字符才会传递给ToHex。您可以尝试使用以下方法之一来解决这个问题:

std::string tohexed = ToHex(std::string(memblock, memblock+size), true);
std::string tohexed = ToHex(std::string(memblock, size), true);

好的...十六进制转换已经可以了...但我还有一个问题:结果并不完全相同。现在47变成了00,或者2D变成了05,所有非ASCII字符也是如此。 - user562854
@develroot - 如果有帮助的话,你的 ToHex 程序中存在符号扩展错误。尝试使用 (s[i]&0xff) 替代 (int)s[i] - Robᵩ
这太棒了! :) - ReinstateMonica3167040

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接