【问题标题】:C++ reading binary filesC++ 读取二进制文件
【发布时间】:2017-10-01 15:06:41
【问题描述】:

我想了解如何在 C++ 中读取二进制文件。 我的代码:

int main() {
    ifstream ifd("input.png",ios::binary |ios::ate);
    int size = ifd.tellg();
    ifd.seekg(0,  ios::beg);
    vector<char> buffer;
    buffer.reserve(size);
    ifd.read(buffer.data(), size);

    cout << buffer.data();
    return 0;
}

我认为如果我计算缓冲区,我会得到二进制的结果,但事实并非如此。

My output is: ˙Ř˙á6Exif

如果我阅读文本文件,它会以正常形式而不是二进制形式显示文本。显然我的逻辑不在这里。 如何将文件读取到缓冲区以使其包含二进制值? 附:我这样做是为了实现 Shannon-Fano 算法,所以如果有人对读取二进制文件有任何建议,我将不胜感激。

【问题讨论】:

  • 您的控制台不会打印二进制文件,它会尝试理解二进制数据,就好像它是文本 + 一些控制代码一样
  • 您打开了一个图片文件image.png,其中(大概)包含二进制编码的图像数据(也就是一组红/绿/蓝强度级别或类似的东西)。
  • @MarkoMlakar 是的,数据是二进制的。如果它是二进制或文本,在 C++ 中真的没有区别。通过使用ios::binary 打开文件,您可以确保不会发生文本转换。
  • 听起来你误解了这里的“二进制”是什么意思。您的 [破碎] 假设/期望的一个示例将使我们能够更好地调整我们的答案。

标签: c++ file binary


【解决方案1】:

您需要调整矢量的大小,而不是保留它:

int main()
{
    ifstream ifd("input.png", ios::binary | ios::ate);
    int size = ifd.tellg();
    ifd.seekg(0, ios::beg);
    vector<char> buffer;
    buffer.resize(size); // << resize not reserve
    ifd.read(buffer.data(), size);

    cout.write(buffer.data(), buffer.size()); // you cannot just output buffer to cout as the buffer won't have '\0' ond-of-string terminator
}

否则,您的代码会尝试将 size 字符读入空缓冲区。您也可以使用设置向量大小的向量构造函数:vector&lt;char&gt; buffer(size);

您可以通过这种方式输出缓冲区的字节值:

void dumpbytes(const vector<char>& v)
{
    for (int i=0; i<v.size(); ++i)
    {
        printf("%u ", (unsigned char)v[i]);
        if ((i+1) % 16 == 0)
            printf("\n");
    }
    printf("\n");
}

或者像普通十六进制编辑器对十六进制输出所做的那样:

void dumphex(const vector<char>& v)
{
    const int N = 16;
    const char hex[] = "0123456789ABCDEF";
    char buf[N*4+5+2];
    for (int i = 0; i < v.size(); ++i)
    {
        int n = i % N;
        if (n == 0)
        {
            if (i)
                puts(buf);
            memset(buf, 0x20, sizeof(buf));
            buf[sizeof(buf) - 2] = '\n';
            buf[sizeof(buf) - 1] = '\0';
        }
        unsigned char c = (unsigned char)v[i];
        buf[n*3+0] = hex[c / 16];
        buf[n*3+1] = hex[c % 16];
        buf[3*N+5+n] = (c>=' ' && c<='~') ? c : '.';
    }
    puts(buf);
}

使用“Hello World!”缓冲数据将按如下方式打印:

48 65 6C 6C 6F 20 57 6F 72 6C 64 21                  Hello World!

【讨论】:

  • 谢谢你的回答,但结果是一样的
  • @MarkoMlakar 如果您的文件包含二进制数据,您为什么要尝试将该数据发送到cout?尝试阅读文本文件,你会看到你的文本。
  • 我认为如果我输入图像,它会计算出构成该图像的位
  • 这是一个不错的小技巧,您可以使用。 here
  • @MarkoMlakar 就是这样做的!如果您的文件包含 4 个字节且值为 [20, 20, 20, 20],那么您的代码将输出空格,如 ' ' == 20cout the bits that make that image - 你的意思是十六进制还是二进制?无论哪种方式,您都需要手动转换数据。关键是,通过我的更改,您的代码应该可以正确读取您的文件。
【解决方案2】:

以二进制模式打开文件意味着您的操作系统不会透明地转换 CR/LF/CRLF 格式之间的行尾。

它对您的计算机在七行之后打印字符串的方式完全没有任何影响。我不知道“以二进制形式获取结果”是什么意思,但我建议通过以十六进制对表示形式一次打印其组成字节来呈现您的 vector&lt;char&gt; 的内容:

std::cout << std::hex << std::setfill('0');
for (const auto byte : buffer)
   std::setw(2) << byte;

输出将类似于:

0123456789abcdef0123456789abcdef

每两个字符代表数据中一个字节的 0-255 字节值,使用 base-16(或“十六进制”)数字系统。这是非文本信息的常见表示形式。

或者,you could output the data in base-2(字面意思是“二进制”)。

如何呈现信息由您决定。文件打开方式与你的矢量无关。

您还需要修复矢量的大小;此刻你打电话给.reserve,而你的意思是.resize

【讨论】:

    【解决方案3】:

    根据 Pavel 的回答,您还可以添加此以查看真正的二进制数据,即0's 和1s。不要忘记包含 bitset 标头。

    void dumpbin(const vector<char>& v)
    {
        for (int i = 0; i < v.size(); ++i)
        {
            cout <<bitset<8>((unsigned char)(v[i])) << " ";
            if ((i + 1) % 8 == 0)
                printf("\n");
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-09-03
      • 2016-01-15
      • 1970-01-01
      • 2011-02-03
      • 2015-08-22
      • 2012-08-19
      • 2011-10-20
      • 2013-07-24
      • 2019-05-16
      相关资源
      最近更新 更多