【问题标题】:creating a c++ program that displays hexadecimal-formatted data from a bmp file创建一个显示来自 bmp 文件的十六进制格式数据的 c++ 程序
【发布时间】:2018-07-16 00:04:56
【问题描述】:

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

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

我有什么:

我想让它看起来像什么:

这是我的代码:

#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;

}

【问题讨论】:

  • 你必须更好地解释你在寻找什么作为输出。左栏的标题是什么意思?
  • 对不起,不是标题,我的意思是 bmp 地址在左列。我附上了我当前输出的图像以及我的输出需要的样子。
  • 您可能会考虑 C++ 函数 std::string dumpByteHex(...) 答案:stackoverflow.com/a/46083427/2785528
  • 我删除了标签bmp,因为您的代码并不是真正的关于 BMP 文件。这可以询问任何文件类型(甚至任何十六进制转储)。

标签: c++ binary hex


【解决方案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;
}

可能有一种奇特的方法可以做到这一点,但当我使用 iostreams 查找特定输出时,我通常会使用蛮力。

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

【讨论】:

    【解决方案2】:

    使用% 运算符在每 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) << " ";
    }
    

    【讨论】:

      【解决方案3】:

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

      在另一个答案中,我提交了这种形式的 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...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-01
        • 2010-12-09
        • 2014-12-20
        • 2013-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多