使用 c++ 时从二进制文件中读取 int 不正确

Posted

技术标签:

【中文标题】使用 c++ 时从二进制文件中读取 int 不正确【英文标题】:Reading int from binary file incorrect when using c++ 【发布时间】:2018-05-22 16:43:50 【问题描述】:

我有一个复杂的结构化二进制文件。我在 python 中创建了一个解析器来读取二进制文件并转换为正确的值并将数据保存到 csv 以便可以分析这些值。这很好用,但有些文件非常大(即 20+ Gb)并且需要很多小时来解析。我试图通过在 c++ 中实现相同的过程来加快速度。

下面是一段摘录,它在每个逻辑记录的开头读取一个控制字并指定记录的大小。对于特定情况,控制字为 128(4 字节,Big Endian,int)。在python中我这样做:

x = open(str(self.filename), "rb")
cw_d_type = np.dtype('>i4')
temp = np.frombuffer(x.read(cw_d_type.itemsize), dtype=cw_d_type)

在此之后 temp[0] 中的值为 128。现在,当我尝试使用以下代码在 c++ 中做同样的事情时

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <sstream>
#include <stdint.h>

using namespace std

struct control_word

    uint32_t chunk_size;


int main()

    // define my stream
    ifstream in_f("Y:/path_to_binary_file/binary_file", ios::binary | ios::in | ios::ate);

    // find the size of the file
    int file_size = in_f.tellg();

    // goto the beginning of the file
    in_f.seekg(0, std::ios::beg);

    in_f.read(reinterpret_cast<char*>(&cw), sizeof(cw));
    cout << cw.chunk_size << endl

    ... continue reading the rest of the structures


cw.chunk_size = 2147483648 的结果。我知道我正在读取文件 b/c 中的正确位置,我读取的下一个结构有一个 32 位字符串,如果我不在,它正在被正确读取文件中的正确位置,那么结果将不正确。

如果我将控制字结构从int 更改为char[4],则结果是[0][0][0][-128],除了负号之外几乎是正确的。

我读到的所有双精度和浮点数都显示相同的内容。唯一似乎可以正确读取的是char 值。自从我上次用 C++ 编程已经有好几年了。有什么我忘记做的事情来正确地将我的二进制文件映射到我的结构中吗?

我已经阅读了许多有关读取二进制文件的问题,但无法弄清楚为什么我会得到这些奇怪的值。我找到的最接近的答案is here,解决方案是用户没有将二进制块映射到正确的类型。我知道在我的 python 实现中这不是我 b/c 的情况,我将块读取为 int 并得到我期望的值。

【问题讨论】:

请编辑您的问题以包含minimal reproducible example @MarkSetchell 和 @ricco19 std::istream::read 期望 char * 作为第一个参数,你的建议是错误的和无用的。 @Slava 谢谢你的好意。我已经删除了我的恶魔般无用的评论并投票给你的答案:-) @ricco19 在代码中显示有一个转换为char *,将转换替换为unsigned char * 不会给 OP 任何东西,并且可能会产生警告。如果你的意思是别的,你可能应该更清楚。 【参考方案1】:

根据documentation > for numpy.dtype 指定Big-Endian 格式。您很可能在 Intel 或 Little-Endian 兼容的 CPU 上运行您的代码。您需要使用ntohl() 函数转换您的uint32_t 字段:

in_f.read(reinterpret_cast<char*>(&cw), sizeof(cw));
cw.chunk_size = ntohl( cw.chunk_size );
cout << cw.chunk_size << endl;

关于Endianness的详细信息

【讨论】:

谢谢,这解决了我的问题!要使用 Winsock 命令,我必须 #include winsock.h,然后通过转到 Project>Poperties>Linker>Input>Additional Dependencies 并输入 Ws2_32.lib,将另一个库添加到我的 Visual Studio。

以上是关于使用 c++ 时从二进制文件中读取 int 不正确的主要内容,如果未能解决你的问题,请参考以下文章

如何从二进制文件中读取int型序列

从二进制文件中读取矩阵

PHP如何将从二进制文件中读取的字节转换为数字

无法使用 fstream 从二进制文件中读取字符串,而是显示奇怪的符号

从二进制文件中读取并转换为双精度?

用python从二进制文件中读取32位带符号的ieee 754浮点?