用C ++写入二进制文件
writing to a binary file in c++
我的问题是我有一个十六进制表示的字符串说:
036e
。我想以相同的十六进制表示形式将其写入二进制文件。我首先使用 sstrtoul()
函数将字符串转换为整数。然后
我使用 fwrite()
函数将其写入文件。这是我写的代码。在 运行 this:
之后,我的文件中得到以下输出
6e03 0000
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ofstream fileofs("binary.bin", ios::binary | ios::out);
string s = "036e";
int x = strtoul(s.c_str(), NULL, 16);
fileofs.write((char*)&x, sizeof(int));
fileofs.close();
}
虽然我期望的结果是这样的:
036e
谁能准确解释一下我做错了什么?
您的问题与 endianees 以及整数的大小有关。
对于反转字节,解释是您 运行 在小端系统中。
对于额外的 2 个零,解释是您使用的是 32 位编译器,其中 int 有 4 个字节。
只要您要始终在 32 位小端系统中使用代码,就没有问题。
如果您保留系统,如果您使用类似的代码从文件中读取整数,您将获得正确的值(您的第一个读取整数将为 0x36E)。
要按照您的意愿写入数据,您可以使用完全相同的代码,只需进行如下所述的微小改动:
unsigned short x = htons(strtoul(s.c_str(), NULL, 16));
fileofs.write((char*)&x, sizeof(x));
但是您必须知道,当您读回数据时,您必须使用 ntohs()
将其转换为正确的格式。如果您以这种方式编写代码,它将在任何编译器和系统中工作,因为网络顺序始终相同,并且转换函数只会在必要时执行数据更改。
您可以找到更多信息on another thread here and in the linux.com man page for those functions。
如果需要 16 位,请使用保证为 16 位的数据类型。 uint16_t
from cstdint 应该可以解决问题。
下一个字节序。
这是 described in detail 很多地方。 TL;DR 版本是一些系统,实际上您可能为其编写代码的每台台式 PC 都使用 BACKWARD 字节存储它们的整数。超出解释原因的范围,但是当您深入了解常见的使用模式时,它确实有意义。
因此,您看到的 036e 是两个字节,03 和 6e,并且首先存储最低有效字节 6e。这样计算机看到的是一个包含 6e03 的两字节值。这是写入输出文件的内容,除非您采取措施强制对输出进行排序。
有很多不同的方法来强制排序,但让我们关注一种总是有效的(即使移植到已经是大端的系统时)并且易于阅读的方法。
uint16_t in;
uint8_t out[2];
out[0] = (in >> 8) & 0xFF; // put highest in byte in first out byte
out[1] = in & 0xFF; // put lowest in byte in second out byte
out
然后写入文件。
Recommended supplementary reading: Serialization 这将有助于解释常见的下一个问题:"Why my strings crash my program after I read them back in?"
我的问题是我有一个十六进制表示的字符串说:
036e
。我想以相同的十六进制表示形式将其写入二进制文件。我首先使用 sstrtoul()
函数将字符串转换为整数。然后
我使用 fwrite()
函数将其写入文件。这是我写的代码。在 运行 this:
6e03 0000
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ofstream fileofs("binary.bin", ios::binary | ios::out);
string s = "036e";
int x = strtoul(s.c_str(), NULL, 16);
fileofs.write((char*)&x, sizeof(int));
fileofs.close();
}
虽然我期望的结果是这样的:
036e
谁能准确解释一下我做错了什么?
您的问题与 endianees 以及整数的大小有关。
对于反转字节,解释是您 运行 在小端系统中。
对于额外的 2 个零,解释是您使用的是 32 位编译器,其中 int 有 4 个字节。
只要您要始终在 32 位小端系统中使用代码,就没有问题。
如果您保留系统,如果您使用类似的代码从文件中读取整数,您将获得正确的值(您的第一个读取整数将为 0x36E)。
要按照您的意愿写入数据,您可以使用完全相同的代码,只需进行如下所述的微小改动:
unsigned short x = htons(strtoul(s.c_str(), NULL, 16));
fileofs.write((char*)&x, sizeof(x));
但是您必须知道,当您读回数据时,您必须使用 ntohs()
将其转换为正确的格式。如果您以这种方式编写代码,它将在任何编译器和系统中工作,因为网络顺序始终相同,并且转换函数只会在必要时执行数据更改。
您可以找到更多信息on another thread here and in the linux.com man page for those functions。
如果需要 16 位,请使用保证为 16 位的数据类型。 uint16_t
from cstdint 应该可以解决问题。
下一个字节序。
这是 described in detail 很多地方。 TL;DR 版本是一些系统,实际上您可能为其编写代码的每台台式 PC 都使用 BACKWARD 字节存储它们的整数。超出解释原因的范围,但是当您深入了解常见的使用模式时,它确实有意义。
因此,您看到的 036e 是两个字节,03 和 6e,并且首先存储最低有效字节 6e。这样计算机看到的是一个包含 6e03 的两字节值。这是写入输出文件的内容,除非您采取措施强制对输出进行排序。
有很多不同的方法来强制排序,但让我们关注一种总是有效的(即使移植到已经是大端的系统时)并且易于阅读的方法。
uint16_t in;
uint8_t out[2];
out[0] = (in >> 8) & 0xFF; // put highest in byte in first out byte
out[1] = in & 0xFF; // put lowest in byte in second out byte
out
然后写入文件。
Recommended supplementary reading: Serialization 这将有助于解释常见的下一个问题:"Why my strings crash my program after I read them back in?"