【问题标题】:Reading & printing binary data as it is from a binary file using C++使用 C++ 从二进制文件中读取和打印二进制数据
【发布时间】:2011-11-22 09:41:16
【问题描述】:

如何读取二进制文件(我不知道它的类型或其中存储的内容)并将0s 和1s 打印到文本文件中?

#include <iostream>
#include <fstream>
#include <string.h>
#include <iomanip>


using namespace std;


int main(int argc, char *argv[])
{
    char ch;
    bool x;
    int i = 0;

    if (argc < 3)
    {
        cout << endl << "Please put in all parameters" << endl;
        return 0;
    }

    char *c = new char[4];

    ifstream fin(argv[1], ios_base::in | ios_base::binary);

    if (!fin.is_open())
    {
        cout << "Error opening input file" << endl;
        return 0;
    }

    if (!strcmp(argv[2], "-file"))
    {
        ofstream fout(argv[3]);

        if (!fout.is_open())
        {
            cout << "Error opening output file" << endl;
            return 0;
        }

        while (fin.read(c, sizeof ch))
        {
            fout << c;
        }

        cout << "Contents written to file successfully" << endl;
        fout.close();
    }
    else if (!strcmp(argv[2], "-screen"))
    {

        cout << endl << "Contents of the file: " << endl;

        while (fin.read((char *)&x,sizeof x))
        {
            cout << x;
        }

        cout << endl;
    }
    else
    {
        cout << endl << "Please input correct option" << endl;
        return 0;
    }

    fin.close();
    return 0;
}

【问题讨论】:

  • 这是作业吗?如果没有,而您只想查看内容,您可以在十六进制编辑器中打开文件进行查看。
  • 是的 - 你试过了吗?如果是这样,为什么不发布您的代码并告诉我们什么不起作用。
  • 是的,这是作业......我会发布代码......
  • @MMavipc,我把代码贴出来了......

标签: c++ file-io binary


【解决方案1】:

是的,只需使用 fstreams 并使用二进制标志打开文件,然后您就可以像普通 fstream 一样处理资源并将其流式传输到文本文件中。如果你想将 0 和 1 转换为字符,它会变得有点复杂。最简单的方法很可能是缓冲无符号字符中的字节,如here,然后尝试通过 sprintf 操作这些字节。

fstream API

sprintf API

【讨论】:

  • @quasiverse:告诉你,sprintf 在 C 和 C++ 中都很出色。
  • @Vlad,c 是 c++ 的子集,这使得该陈述成立。但是,如果人们将 printf 误解为 c++ 操作并继续使用它们而不是基于流的操作,他们可能会错过对后者的任何未来改进。
【解决方案2】:

无论好坏,我发现使用printf 最容易做到这一点:

#include <fstream>
#include <cstdio>

static const std::size_t blocks = 256;
char buf[blocks * 16];

std::ifstream infile(filename, "rb");

do
{
  infile.read(buf, blocks * 16);

  for (std::size_t i = 0; i * 16 < infile.gcount(); ++i)
  {
    for (std::size_t j = 0; j < 16 && 16 * i + j < infile.gcount(); ++j)
    {
      if (j != 0) std::printf(" ");
      std::printf("0x%02X", static_cast<unsigned char>(buf[16 * i + j]));
    }
  }
} while (infile);

为此,我选择了每行 16 字节的任意行长,我一次读取 4kiB ——这可以调整以获得最大效率。使用gcount() 获取实际读取字节数很重要,因为最后一轮循环可能读取不到 4kiB。

请注意,这基本上等同于 hexdump 实用程序。

如果你想要真正的二进制输出,你可以写一个小帮助例程来代替printf

【讨论】:

  • imo,在 c++ 教程中混合 c 会妨碍你学习“正确”的东西。
  • @YeenFei:谁在说教程? :-)
【解决方案3】:

据我所知,您不需要十六进制输出,而是二进制(0 和 1),尽管我不明白为什么。没有用于输出二进制数据的 io 操纵器。您需要使用按位运算符自己执行此操作。像这样的:

char c; // contains byte read from input
for (size_t i = 0; i != sizeof(c); ++i) {
    std::cout << c & 0x80; // grab most significant bit
    c <<= 1; // right shift by 1 bit
} 

【讨论】:

    【解决方案4】:

    最简单的方法可能是从输入中创建一个std::bitset,然后将它们打印出来。忽略错误检查等,一个简单的版本会是这样的:

    #include <bitset>
    #include <fstream>
    #include <iostream>
    #include <ios>
    #include <iomanip>
    
    int main(int argc, char **argv) { 
        std::ifstream infile(argv[1], std::ios::binary);
        char ch;
        unsigned long count = 0;
    
        while (infile.read(&ch, 1)) {
            if (count++ % 4 == 0)
                std::cout << "\n" << std::setw(6) << std::hex << count;
            std::cout << std::setw(10) << std::bitset<8>(ch);
        }   
        return 0;
    }
    

    我认为十六进制的正常转储更有用。我只在上面每行显示四个字节(只有通过省略行首的偏移量才能将 8 个字节放入 80 列中,这将是一个严重的损失,至少根据我的经验),所以整个屏幕通常是只有~200字节左右。在十六进制中,您可以(并且通常会)在每行显示 16 个字节,包括十六进制和(对于可打印字符)本身。

    不过,我应该补充一点,几十年来我一直在使用十六进制转储,所以我的观点至少部分基于偏见而不是真实事实。

    【讨论】:

      猜你喜欢
      • 2021-05-25
      • 2016-06-15
      • 1970-01-01
      • 2019-04-04
      • 2021-07-02
      • 2017-10-01
      • 2011-09-03
      • 2016-01-15
      • 1970-01-01
      相关资源
      最近更新 更多