【发布时间】:2021-02-14 22:24:34
【问题描述】:
我正在对二进制文件进行读写操作。输出读数时出现小错误。
字符串在那里,但只有很少的 sn-ps,例如:(I"�U) (�U) 附加到其中约 30% 的末尾
我在 Ubuntu 上使用 g++ 编译器
简化代码:
struct Db_connection
{
public:
string name;
}
int Db_connection::write_config()
{
ofstream config_f("config.dat", std::ios_base::binary | std::ios_base::out); //open file
string str = name;
int size = str.length();
config_f.write(reinterpret_cast<char *>(&size), sizeof(int)); // write size of string in int size chunk
config_f.write(str.c_str(), size); //write string
config_f.close();
return 0;
}
Db_connection read_config()
{
ifstream config_f("config.dat", std::ios_base::binary | std::ios_base::in);
Db_connection return_obj;
int size;
string data;
config_f.read(reinterpret_cast<char *>(&size), sizeof(int)); // read string size
char buffer[size];
config_f.read(buffer, size); // read string
data.assign(buffer);
return_obj.name = data;
return return_obj;
}
有什么明显的我搞砸了吗?这和endian有关系吗?我试图将代码最小化为绝对必需品
实际代码更复杂。我有一个包含 2 个结构的向量的类。 1 个结构有四个字符串成员,另一个有一个字符串和布尔值。这些函数实际上是该类的成员并(分别)返回该类。函数循环遍历按顺序写入结构成员的向量。
两个怪事:
- 为了调试,我在读取和写入函数的每次迭代中添加了
size和data变量的输出。size两边都准确一致。data在write方面是准确的,但在read方面具有奇怪的特殊字符。我正在查看如下输出:
Read Size: 12
Data: random addy2�U //the 12 human readable chars are there but with 2 extra symbols
- 最后一块数据(一个布尔值)每次都能正常输出,所以我认为不存在文件指针问题。如果相关:每个
bool和int都可以。它只是字符串的一部分。
希望我犯了一个愚蠢的错误,并且可以批评这个最小化的代码。实际示例太长了。
【问题讨论】:
-
首先,停止使用 VLA,即使您的平台上的非标准扩展支持它们。其次,您的写入操作转储字符但没有终止符,您的读取操作读取字符,但没有设置终止符。您正在使用的
std::string的assign方法需要一个终止的字符串。您可以通过多种方式解决此问题,一种简单的方法是data = std::string(buffer, buffer+size);。但正如我所说,放弃 VLA 并改用向量。或者更好的是,如果您的工具链标准足够,只需在设置并访问其中的托管缓冲区后直接读入data。 -
感谢您的评论。如果我使用
new命令分配了一个char 数组,那也将是一个VLA?要使用向量,我会将push_back()逐字节转换为向量? -
现代 c++ 中没有任何地方可以使用
operator new。如果您需要大小为size的临时字符向量,那么std::vector<char> buff(size);就足够了。然后读入buff.data(),请求的字节数不超过size,最后,data = std::string(buff.begin(), buff.end());不需要手动管理的内存生存期;一切都会自行清理。我仍然会确保您对size的读取请求实际上是size,但这是另一个问题。 -
谨防将
int等类型存储在二进制文件中。这不是便携式的。此数据类型的大小是特定于实现的。相反,您应该决定数据大小(例如 16、32、64 位)并使用适当的类型(即来自<cstdint>的内容,例如uint32_t)写入它。需要额外的预防措施来确保字节序兼容性。适当可移植的应用程序将选择正确的数据类型,然后创建一种方法以选择的字节序读取/写入该数据类型。 -
无论你做什么,将二进制
int写入输出都会产生垃圾字符。
标签: c++ binaryfiles