如何在 c++ 中使用二进制文件输入/输出读取/写入结构的字符串类型成员
How to read/write string type member of a struct using binary file in/out in c++?
>我有 2 个 c++ 代码:一个用于将数据写入二进制文件,另一个用于读取该文件。
write.cpp
代码如下:
#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51;
struct Data
{
char name[NAME_SIZE];
int age;
};
int main()
{
Data person;
char again;
fstream people("people.db", ios::out | ios::binary);
do
{
cout << "Enter the following data about a "<< "person:n";
cout << "Name: ";
cin.getline(person.name, NAME_SIZE);
cout << "Age: ";
cin >> person.age;
cin.ignore();
people.write(reinterpret_cast<char *>(&person),sizeof(person));
cout << "Do you want to enter another record? ";
cin >> again;
cin.ignore();
} while (again == 'Y' || again == 'y');
people.close();
return 0;
}
read.cpp
代码如下:
#include <iostream>
#include <fstream>
using namespace std;
const int NAME_SIZE = 51;
struct Data
{
char name[NAME_SIZE];
int age;
};
int main()
{
Data person;
char again;
fstream people;
people.open("people.db", ios::in | ios::binary);
if (!people)
{
cout << "Error opening file. Program aborting.n";
return 0;
}
cout << "Here are the people in the file:nn";
people.read(reinterpret_cast<char *>(&person),sizeof(person));
while (!people.eof())
{
cout << "Name: ";
cout << person.name << endl;
cout << "Age: ";
cout << person.age << endl;
cout << "nPress the Enter key to see the next record.n";
cin.get(again);
people.read(reinterpret_cast<char *>(&person),sizeof(person));
}
cout << "That's all the data in the file!n";
people.close();
return 0;
}
上面提到的代码工作正常。当我在结构中使用字符串类型成员时出现问题:
新write.cpp
:
#include <iostream>
#include <fstream>
using namespace std;
struct Data
{
string name;
int age;
};
int main()
{
Data person;
char again;
fstream people("people.db", ios::out | ios::binary);
do
{
cout << "Enter the following data about a "<< "person:n";
cout << "Name: ";
cin>>person.name;
cout << "Age: ";
cin >> person.age;
cin.ignore();
people.write(reinterpret_cast<char *>(&person),sizeof(person));
cout << "Do you want to enter another record? ";
cin >> again;
cin.ignore();
} while (again == 'Y' || again == 'y');
people.close();
return 0;
}
新read.cpp
:
#include <iostream>
#include <fstream>
using namespace std;
struct Data
{
string name;
int age;
};
int main()
{
Data person;
char again;
fstream people;
people.open("people.db", ios::in | ios::binary);
if (!people)
{
cout << "Error opening file. Program aborting.n";
return 0;
}
cout << "Here are the people in the file:nn";
people.read(reinterpret_cast<char *>(&person),sizeof(person));
while (!people.eof())
{
cout << "Name: ";
cout << person.name << endl;
cout << "Age: ";
cout << person.age << endl;
cout << "nPress the Enter key to see the next record.n";
cin.get(again);
people.read(reinterpret_cast<char *>(&person),sizeof(person));
}
cout << "That's all the data in the file!n";
people.close();
return 0;
}
现在,当我运行read.cpp
程序无法读取字符串并且程序崩溃时。我必须使用字符串作为结构的成员。如何解决这个问题?
想到的唯一方法是单独写入以下数据:
- 字符串的长度。
- 字符串的字符数组。
- 年龄。
并单独阅读它们。
创建函数来写入/读取Data
实例,以便它们了解彼此的实现策略。
std::ostream& write(std::ostream& out, Data const& data)
{
size_t len = data.name.size();
out.write(reinterpret_cast<char const*>(&len), sizeof(len));
out.write(data.name.c_str(), len);
out.write(reinterpret_cast<char const*>(&data.age));
return out;
}
std::istream& read(std::istream& in, Data& data)
{
size_t len;
in.read(reinterpret_cast<char*>(&len), sizeof(len));
char* name = new char[len+1];
in.read(name, len);
name[len] = ' ';
data.name = name;
delete [] name;
in.read(reinterpret_cast<char*>(&data.age));
return in;
}
并像使用第一种方法一样使用它们。
而不是使用
people.write(reinterpret_cast<char *>(&person),sizeof(person));
用
write(people, person);
而不是使用
people.read(reinterpret_cast<char *>(&person),sizeof(person));
用
read(people, person);
一个问题是sizeof(person.Name)
没有给出你认为它所做的事情。它总是提供相同的大小(在我的例子中为 28 字节),无论您分配给您的人什么字符。名称字符串。这是因为 std::string 至少包含:
- 指向实际字符串的指针
- 其他数据结构,以保存可用大小和所用大小
因此,您不能调用people.write(reinterpret_cast<char *>(&person),sizeof(person));
。字符串的内容不位于 &person
(它位于 std::string 中的指针指向的任何位置)
那么,当您从文件中读取cout << person.name << endl;
后执行时会发生什么?你实际上已经阅读了person.name
的字符串指针指向的地址(而不是内容),当你写人给人.db时。这当然不是一个有效的内存位置,在从您的文件中读取它之后,再次。
以下代码片段可能对您的情况有所帮助。可以使用分隔符和预定义的字符串长度,而不是写入字符串的长度。
constexpr char delimiter = ' ';
constexpr uint32_t maxStringSize = 1024;
struct Data
{
string name;
int age;
};
写入文件时,在字符串后放置一个delimiter
.
假设我们有一个Data structure {"John", 42}
那么我们将写如下:
std::ofstream outStream(filename, std::ios::binary);
outStream << structure.name << delimiter << structure.age;
outStream.close();
读取文件不是写入的镜像(不幸的是).
我们将使用 std::ifstream::getline
来读取字符串,而无需知道它的大小。(错误检查省略)
std::ifstream istrm(filename, std::ios::binary);
Data dataRead;
// string input - use a buffer and look for the next delimiter
char* buf = new char[maxStringSize];
istrm.getline(buf, maxStringSize, delimiter);
dataRead.name = std::string(buf);
// the number input
istrm >> dataRead.age;
对于如何读取/写入此struct
向量的灵感,您可以查看我的存储库。
- 将结构向量保存到文件中,并从C++文件中读取结构向量
- 从只读内存中读取结构
- 从包含 IP 标头片段的二进制文件中读取结构的最佳方法是什么
- 读取结构化文件
- CPP 在读取结构数据时无限循环错误?
- 打开文件以读取结构数组
- 无效操作数以二进制读取结构的阵列
- 读取结构数组时出错
- 如何从另一个类读取结构成员
- 读取结构 -- uint32 不命名类型
- 从流或字节中读取结构时遇到问题
- 读取结构C++二进制文件的运行时错误
- 从二进制文件读取结构数据时获取垃圾值
- 在 c++ 中向二进制文件写入/读取结构
- 在C++文件中写入和读取结构体的三维矢量
- C++按字段读取结构,并将结构直接写入流
- 从LISP的套接字中读取c++结构
- 读取结构化二进制文件c++
- C++二进制文件正在读取结构
- 从CArchive保存的二进制数据中读取结构数组