从文件中读取错误值
Reading wrong values from file
我是 C++ 编码新手。我的应用程序需要将变量写入文件,然后我想再次读取它们来做一些工作。
我将值分配给变量,然后转储到文件中,但是当我读取文件并检查变量时,它分配了不同的值。
以下是我正在使用的 3 个结构。
struct fence_t
{
uint8_t b:1;
uint8_t fence_1:2;
uint8_t fence_2:2;
uint8_t res:3;
};
struct head_t
{
uint8_t format;
fence_t fence;
};
struct pack_t
{
head_t header;
.
.
.
}
我已经分配了 format = 2
packet[i].header.format=2;
packet[i].header.fence.b=0;
packet[i].header.fence.fence_1=2;
packet[i].header.fence.fence_2=2;
packet[i].header.fence.res=0;
这就是我打开文件并在其中转储数据的方式。我希望值以十六进制格式写入。
f = fopen("packets.txt","w");
fprintf(f, "%04X", packet[i].header);
现在我想在另一个函数中读取文件。
ff.seekg(0,ios::end);
size=ff.tellg();
memblock = new pack_t [size/sizeof(pack_t)];
ff.seekg(0,ios::beg);
ff.read((char *)memblock,size);
void * p = (void *)memblock;
for(int i=0;i<3;i++)
{
struct q_entry_t t = {i, p};
queue1.push_back(t);
p = (void *)((uintptr_t)p+64);
}
当我检查格式的值时,它显示 1。
cout<<((head_t *)p)->format<<endl;
这是当我查看 p
的值时 Visual Studio 中内存 window 的输出
0x026A54B8 31 34 30 32 30 30 30 31 30 31 30 30 30 30 30 31 30 30 140200010100000100
有几个问题:
你通过 fprintf()
中的值传递 packet[i].header
,并告诉 fptrintf()
那是一个 int
并且它的值应该以 ascii 十六进制形式写入格式。您的编译器可能会以 int
的大小传递您的值,您将获得一个可用的值。但是您的编译器也可能传递比 int 多或少的数据(因为您的 header 是一个结构并且可能会受到对齐填充的影响),然后,您将写入的值将不是您所期望的。所以它非常依赖于实现。
顺便说一句,即使您的编译器传递了适当大小的值,由于字节序,您可能有 non-portable 个文件。
然后,你读取你的数据,就好像它是二进制的(不打开文件,因为 "rb" 无论如何都会造成破坏)。因此,您将只读取一部分 ascii 数据,并以完全不同的方式解释编码(即您写入“1”,但您将读取 0x31)。那也行不通。你必须按照与你写的相同的逻辑用 fscanf()
来阅读它。但如上所述,这非常依赖于实现。
作为简单的替代方法,我建议您使用 ios::binary
以二进制 fstreams 打开文件,并使用 write()
/read()
写入内存块,使用数据元素的地址及其确切的大小。
作为一种更便携的替代方案,您可以使用文本文件流,并为类型 head_t
重载 <<
和 >>
以使用控制良好的(即固定字节顺序)十六进制格式。
一般来说,如果你用 fprintf 写,然后用 fscanf 或 getline 读回;即面向行/ASCII 的输入机制。
如果您希望文件是结构化的二进制文件,那么使用write 写入,使用read 读取。
不要混淆这两种机制
我是 C++ 编码新手。我的应用程序需要将变量写入文件,然后我想再次读取它们来做一些工作。
我将值分配给变量,然后转储到文件中,但是当我读取文件并检查变量时,它分配了不同的值。 以下是我正在使用的 3 个结构。
struct fence_t
{
uint8_t b:1;
uint8_t fence_1:2;
uint8_t fence_2:2;
uint8_t res:3;
};
struct head_t
{
uint8_t format;
fence_t fence;
};
struct pack_t
{
head_t header;
.
.
.
}
我已经分配了 format = 2
packet[i].header.format=2;
packet[i].header.fence.b=0;
packet[i].header.fence.fence_1=2;
packet[i].header.fence.fence_2=2;
packet[i].header.fence.res=0;
这就是我打开文件并在其中转储数据的方式。我希望值以十六进制格式写入。
f = fopen("packets.txt","w");
fprintf(f, "%04X", packet[i].header);
现在我想在另一个函数中读取文件。
ff.seekg(0,ios::end);
size=ff.tellg();
memblock = new pack_t [size/sizeof(pack_t)];
ff.seekg(0,ios::beg);
ff.read((char *)memblock,size);
void * p = (void *)memblock;
for(int i=0;i<3;i++)
{
struct q_entry_t t = {i, p};
queue1.push_back(t);
p = (void *)((uintptr_t)p+64);
}
当我检查格式的值时,它显示 1。
cout<<((head_t *)p)->format<<endl;
这是当我查看 p
的值时 Visual Studio 中内存 window 的输出0x026A54B8 31 34 30 32 30 30 30 31 30 31 30 30 30 30 30 31 30 30 140200010100000100
有几个问题:
你通过
fprintf()
中的值传递packet[i].header
,并告诉fptrintf()
那是一个int
并且它的值应该以 ascii 十六进制形式写入格式。您的编译器可能会以int
的大小传递您的值,您将获得一个可用的值。但是您的编译器也可能传递比 int 多或少的数据(因为您的 header 是一个结构并且可能会受到对齐填充的影响),然后,您将写入的值将不是您所期望的。所以它非常依赖于实现。顺便说一句,即使您的编译器传递了适当大小的值,由于字节序,您可能有 non-portable 个文件。
然后,你读取你的数据,就好像它是二进制的(不打开文件,因为 "rb" 无论如何都会造成破坏)。因此,您将只读取一部分 ascii 数据,并以完全不同的方式解释编码(即您写入“1”,但您将读取 0x31)。那也行不通。你必须按照与你写的相同的逻辑用
fscanf()
来阅读它。但如上所述,这非常依赖于实现。
作为简单的替代方法,我建议您使用 ios::binary
以二进制 fstreams 打开文件,并使用 write()
/read()
写入内存块,使用数据元素的地址及其确切的大小。
作为一种更便携的替代方案,您可以使用文本文件流,并为类型 head_t
重载 <<
和 >>
以使用控制良好的(即固定字节顺序)十六进制格式。
一般来说,如果你用 fprintf 写,然后用 fscanf 或 getline 读回;即面向行/ASCII 的输入机制。
如果您希望文件是结构化的二进制文件,那么使用write 写入,使用read 读取。
不要混淆这两种机制