创建一个显示bmp文件中十六进制格式数据的c ++程序

时间:2018-02-06 01:55:59

标签: c++ binary hex

我正在尝试创建一个以十六进制形式显示bmp文件输出的程序。到目前为止,我得到了输出,但我需要以某种方式组织它。

需要组织的方式是将bmp文件的地址放在左栏中,然后按照它们在文件中出现的顺序在每行中以十六进制形式显示16字节的数据。同时在每8个字节之间留出一个额外的空间。到目前为止,我得到了十六进制显示,我只需要帮助组织它。

我有什么:

image

我想让它看起来像:

image

这是我的代码:

#include <iostream>     // cout
#include <fstream>      // ifstream
#include <iomanip>      // setfill, setw
#include <stdlib.h>


using namespace std;  // Use this to avoid repeated "std::cout", etc.

int main(int argc, char *argv[])  // argv[1] is the first command-line argument
[enter image description here][1]{


// Open the provided file for reading of binary data
ifstream is("C:\\Users\\Test\\Documents\\SmallTest.bmp", ifstream::binary);
if (is)   // if file was opened correctly . . . 
{

    is.seekg(0, is.end);   // Move to the end of the file
    int length = is.tellg();   // Find the current position, which is file length
    is.seekg(0, is.beg);  // Move to the beginning of the file

    char * buffer = new char[length]; // Explicit allocation of memory.

    cout << "Reading " << length << " characters... ";
    is.read(buffer, length);  // read data as a block or group (not individually)

    if (is)
        cout << "all characters read successfully.\n";
    else
        cout << "error: only " << is.gcount() << " could be read.\n";
    is.close();

    // Now buffer contains the entire file. The buffer can be printed as if it
    // is a _string_, but by definition that kind of print will stop at the first
    // occurrence of a zero character, which is the string-ending mark.
    cout << "buffer is:\n" << buffer << "\n";  // Print buffer

    for (int i = 0; i < 100; i++)  // upper range limit is typically length
    {


        cout << setfill('0') << setw(4) << hex << i << "   ";

        cout << setfill('0') << setw(2) << hex << (0xff & (int)buffer[i]) << " ";
    }

    delete[] buffer; // Explicit freeing or de-allocation of memory.
}
else // There was some error opening file. Show message.
{
    cout << "\n\n\tUnable to open file " << argv[1] << "\n";
}

return 0;

}

3 个答案:

答案 0 :(得分:1)

你可以这样做:

#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cctype>

std::ostream& fullLine(std::ostream& out, const std::vector<uint8_t>& v, size_t offset)
{
    //save stream state so we can restore it after all the hex/setw/setfill nonsense.
    std::ios oldState(0);
    oldState.copyfmt(out);

    out << std::hex << std::setfill('0') << std::setw(8) << offset << "  ";
    for (size_t i = 0; i < 16; ++i)
    {
        if (i == 8) out << " ";
        out << std::hex << std::setfill('0') << std::setw(2) << static_cast<uint32_t>(v[i + offset]) << " ";
    }
    out << " ";

    //restore stream state to print normal text
    out.copyfmt(oldState);
    for (size_t i = 0; i < 16; ++i)
    {
        out << (std::isprint(v[i + offset]) ? static_cast<char>(v[i + offset]) : '.');
    }
    out << "\n";
    return out;
}

int main()
{
    std::vector<uint8_t> data;
    std::ifstream f("test.txt", std::ios::binary);
    if (f)
    {
        f.seekg(0, f.end);
        data.resize(static_cast<size_t>(f.tellg()));
        f.seekg(0, f.beg);
        f.read((char*)data.data(), data.size());
        const size_t numFullLines = data.size() / 16;
        const size_t lastLineLength = data.size() % 16;
        for (size_t i = 0; i < numFullLines; ++i)
        {
            if (!fullLine(std::cout, data, i * 16))
            {
                std::cerr << "Error during output!\n";
                return -1;
            }
        }
    }
    return 0;
}

这可能是一种奇特的方式,但是当我使用iostream寻找特定输出时,我通常会蛮力。

如何处理部分最后一行取决于您。 :)

答案 1 :(得分:0)

使用%运算符在每第16次计数后断行:

cout << hex;
for(int i = 0; i < 100; i++)  
{
    if(i && (i % 16) == 0)
        cout << "\n";
    cout << setfill('0') << setw(2) << (buffer[i] & 0xFF) << " ";
}

答案 2 :(得分:0)

  

我需要以某种方式组织它。

在另一个答案中,我提交了这种形式的dumpByteHex()...也许它可以帮助你实现你想要的。 (另见https://stackoverflow.com/a/46083427/2785528

// C++ support function
std::string  dumpByteHex (char*       startAddr,  // reinterpret_cast explicitly
                          size_t      len,        //     allows to char* from T*
                          std::string  label = "",
                          int          indent = 0)    
{
   std::stringstream ss;

   if(len == 0) {
      std::cerr << "\n  dumpByteHex() err: data length is 0? " << std::endl << std::dec;
      assert(len != 0);
   }

   // Output description
   ss << label << std::flush;

   unsigned char* kar = reinterpret_cast<unsigned char*>(startAddr); // signed to unsigned

   std::string echo;  // holds input chars until eoln

   size_t indx;
   size_t wSpaceAdded = false;
   for (indx = 0; indx < len; indx++)
   {
      if((indx % 16) == 0)
      {
         if(indx != 0) // echo is empty the first time through for loop
         {
            ss << "  " << echo << std::endl;
            echo.erase();
         }

         // fields are typically < 8 bytes, so skip when small
         if(len > 7) {
            if (indent) { ss << std::setw(indent) << "  "; }
            ss << std::setfill('0') << std::setw(4) << std::hex
               << indx   << " " << std::flush;
         } // normally show index
      }

      // hex code
      ss << " " << std::setfill('0') << std::setw(2) << std::hex
         << static_cast<int>(kar[indx]) << std::flush;

      if((indx % 16) == 7) { ss << " "; wSpaceAdded = true; } // white space for readability

      // defer the echo-of-input, capture to echo
      if (std::isprint(kar[indx])) { echo += kar[indx]; }
      else                         { echo += '.'; }
   }

   // finish last line when < 17 characters
   if (((indx % 16) != 0) && wSpaceAdded) { ss << "  ";  indx++; } // when white space added
   while ((indx % 16) != 0)               { ss << "   "; indx++; } // finish line

   // the last echo
   ss << "   " << echo << '\n';

   return ss.str();
} // void dumpByteHex()

输出格式:

0000  11 22 33 44 55 66 00 00  00 00 77 88 99 aa        ."3DUf....w...