![](/img/trans.png)
[英]c++ read and write struct array with std::string into binary file
[英]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:\n\n";
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:\n\n";
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] = '\0';
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)
不能提供您认为的功能。 无论您分配给person.Name字符串是什么字符,它始终具有相同的大小(在我的情况下为28个字节)。 这是因为std :: string至少包含:
因此,您无法调用people.write(reinterpret_cast<char *>(&person),sizeof(person));
。 字符串的内容不位于&person
(它位于std :: string中的指针所指向的位置)
因此,当执行cout << person.name << endl;
时会发生什么? 从您的文件中读取后? 当您将人写到people.db时,您实际上已经读取了person.name
的字符串指针指向的地址(而不是内容)。 再次从文件中读取后,这当然不是有效的内存位置。
以下代码片段可能对您的情况有所帮助。 可以使用定界符和预定义的字符串长度来代替写入字符串的长度。
constexpr char delimiter = '\0';
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
的向量的灵感,您可以查看我的存储库。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.