如何在二进制文件中存储 class 具有字符串的对象?
How to store class object having string in binary file?
我正在将我的 class 对象存储在二进制文件中,但是当我加载数据时我得到了奇怪的结果。
以下代码正在加载和保存数据:
#include <iostream>
#include <fstream>
#include <memory>
#include <string>
#include <sstream>
using namespace std;
template <class C>
void Load(const char fileName[], C& obj)
{
ifstream in;
in.open(fileName, ios::in | ios::binary);
in.read(reinterpret_cast<char*>(addressof(obj)), sizeof(obj));
in.close();
return;
}
template <class T>
void Save(const char fileName[], T obj)
{
ofstream out;
out.open(fileName, ios::out | ios::binary);
out.write(reinterpret_cast<char const*>(addressof(obj)), sizeof(obj));
stringstream ss;
out.close();
return;
}
class Contact {
public:
int CompareTo(Contact obj)
{
return 1;
}
string ss;
int rollNum;
};
class Data {
public:
Data()
{
}
Contact arr[10];
};
int main()
{
const char fileName[] = "ContactMG.dat";
/*
Data *T = new Data();
for(int i=0;i<10;i++)
T->arr[i].ss = "fahad";
Save(fileName , *T);
*/
Data* d = new Data();
Load(fileName, *d);
for (int i = 0; i < 10; i++)
cout << d->arr[i].ss << endl;
}
/*
Console outPut:
ⁿx
p²x
σß╥Z∙
░▒▓│┤
>
☺Y╩
░‼╩
*/
/* Binary File
@® ® ®
*/
I want to ask how I can store this object in the binary file and load it?
我很确定问题出在字符串上,但我不知道如何解决!
我已经知道将字符串存储在二进制文件中,但不知道如何存储 class 中包含字符串的对象
我会引入一个新的间接级别,即函数 from_binary
和 to_binary
,并根据这些实现您的 Load
和 Store
:
template <class C>
bool Load(const char fileName[], C& obj) {
if (ifstream in{fileName, ios::in | ios::binary}) {
from_binary(in, obj);
return true;
}
return false;
}
template <class T>
bool Save(const char fileName[], T obj) {
if (ofstream out{fileName, ios::out | ios::binary}) {
to_binary(out, obj);
return true;
}
return false;
}
对于 POD 数据类型,from_binary
和 to_binary
将执行您在 Load
/Store
中已经执行的操作(但是请注意:指针是 PODs 但保存地址几乎没有意义):
template <class T, typename = enable_if_t<is_pod_v<T>>>
void from_binary(ifstream& in, T& obj) {
in.read(reinterpret_cast<char*>(addressof(obj)), sizeof(obj));
}
template <class T, typename = enable_if_t<is_pod_v<T>>>
void to_binary(ofstream& out, T const& obj) {
out.write(reinterpret_cast<char const*>(addressof(obj)), sizeof(obj));
}
正如评论中指出的那样,std::string
不是 POD 类型。我将通过保存字符数然后保存实际字符来序列化它:
void from_binary(ifstream& in, string& str) {
std::size_t stringSize{0};
from_binary(in, stringSize);
str.reserve(stringSize);
for (size_t i = 0; i != stringSize; ++i) {
char ch{};
in.read(&ch, 1);
str.push_back(ch);
}
}
void to_binary(ofstream& out, string const& str) {
auto const stringSize = str.size();
to_binary(out, stringSize);
auto const* cStr = str.c_str();
out.write(cStr, stringSize);
}
此外,我将通过对数组的每个元素调用 to_binary
/from_binary
来 serialize/deserialize 一个数组:
template <class T, size_t N>
void from_binary(ifstream& in, T (&obj)[N]) {
for (auto& elem : obj) from_binary(in, elem);
}
template <class T, size_t N>
void to_binary(ofstream& out, T const (&obj)[N]) {
for (auto const& elem : obj) to_binary(out, elem);
}
上面的函数足以实现你的Contact
和Data
from_binary
和to_binary
类:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
template <class T, typename = enable_if_t<is_pod_v<T>>>
void from_binary(ifstream& in, T& obj) {
in.read(reinterpret_cast<char*>(addressof(obj)), sizeof(obj));
}
template <class T, typename = enable_if_t<is_pod_v<T>>>
void to_binary(ofstream& out, T const& obj) {
out.write(reinterpret_cast<char const*>(addressof(obj)), sizeof(obj));
}
void from_binary(ifstream& in, string& str) {
std::size_t stringSize{0};
from_binary(in, stringSize);
str.reserve(stringSize);
for (size_t i = 0; i != stringSize; ++i) {
char ch{};
in.read(&ch, 1);
str.push_back(ch);
}
}
void to_binary(ofstream& out, string const& str) {
auto const stringSize = str.size();
to_binary(out, stringSize);
auto const* cStr = str.c_str();
out.write(cStr, stringSize);
}
template <class T, size_t N>
void from_binary(ifstream& in, T (&obj)[N]) {
for (auto& elem : obj) from_binary(in, elem);
}
template <class T, size_t N>
void to_binary(ofstream& out, T const (&obj)[N]) {
for (auto const& elem : obj) to_binary(out, elem);
}
template <class C>
bool Load(const char fileName[], C& obj) {
if (ifstream in{fileName, ios::in | ios::binary}) {
from_binary(in, obj);
return true;
}
return false;
}
template <class T>
bool Save(const char fileName[], T obj) {
if (ofstream out{fileName, ios::out | ios::binary}) {
to_binary(out, obj);
return true;
}
return false;
}
class Contact {
public:
int CompareTo(Contact obj) { return 1; }
string ss;
int rollNum;
};
void from_binary(ifstream& in, Contact& obj) {
from_binary(in, obj.ss);
from_binary(in, obj.rollNum);
}
void to_binary(ofstream& out, Contact const& obj) {
to_binary(out, obj.ss);
to_binary(out, obj.rollNum);
}
class Data {
public:
Data() {}
Contact arr[10];
};
void from_binary(ifstream& in, Data& obj) { from_binary(in, obj.arr); }
void to_binary(ofstream& out, Data const& obj) { to_binary(out, obj.arr); }
int main() {
const char fileName[] = "ContactMG.dat";
{
Data data;
auto const contactCount = sizeof(data.arr) / sizeof(data.arr[0]);
for (size_t c = 0; c != contactCount; ++c) {
data.arr[c].ss = "some name " + to_string(c);
data.arr[c].rollNum = c;
}
Save(fileName, data);
}
{
Data data;
Load(fileName, data);
for (auto const& contact : data.arr)
cout << "Contact: rollNum=" << contact.rollNum
<< ", ss=" << contact.ss << '\n';
}
}
输出:
Contact: rollNum=0, ss=some name 0
Contact: rollNum=1, ss=some name 1
Contact: rollNum=2, ss=some name 2
Contact: rollNum=3, ss=some name 3
Contact: rollNum=4, ss=some name 4
Contact: rollNum=5, ss=some name 5
Contact: rollNum=6, ss=some name 6
Contact: rollNum=7, ss=some name 7
Contact: rollNum=8, ss=some name 8
Contact: rollNum=9, ss=some name 9
虽然这可能会解决您的特定问题,但随着项目的增长,from_binary
和 to_binary
所需的重载数量会迅速增加。所以我肯定会检查是否有更全面(且经过良好测试)的库解决方案。
我正在将我的 class 对象存储在二进制文件中,但是当我加载数据时我得到了奇怪的结果。
以下代码正在加载和保存数据:
#include <iostream>
#include <fstream>
#include <memory>
#include <string>
#include <sstream>
using namespace std;
template <class C>
void Load(const char fileName[], C& obj)
{
ifstream in;
in.open(fileName, ios::in | ios::binary);
in.read(reinterpret_cast<char*>(addressof(obj)), sizeof(obj));
in.close();
return;
}
template <class T>
void Save(const char fileName[], T obj)
{
ofstream out;
out.open(fileName, ios::out | ios::binary);
out.write(reinterpret_cast<char const*>(addressof(obj)), sizeof(obj));
stringstream ss;
out.close();
return;
}
class Contact {
public:
int CompareTo(Contact obj)
{
return 1;
}
string ss;
int rollNum;
};
class Data {
public:
Data()
{
}
Contact arr[10];
};
int main()
{
const char fileName[] = "ContactMG.dat";
/*
Data *T = new Data();
for(int i=0;i<10;i++)
T->arr[i].ss = "fahad";
Save(fileName , *T);
*/
Data* d = new Data();
Load(fileName, *d);
for (int i = 0; i < 10; i++)
cout << d->arr[i].ss << endl;
}
/*
Console outPut:
ⁿx
p²x
σß╥Z∙
░▒▓│┤
>
☺Y╩
░‼╩
*/
/* Binary File
@® ® ®
*/
I want to ask how I can store this object in the binary file and load it?
我很确定问题出在字符串上,但我不知道如何解决! 我已经知道将字符串存储在二进制文件中,但不知道如何存储 class 中包含字符串的对象
我会引入一个新的间接级别,即函数 from_binary
和 to_binary
,并根据这些实现您的 Load
和 Store
:
template <class C>
bool Load(const char fileName[], C& obj) {
if (ifstream in{fileName, ios::in | ios::binary}) {
from_binary(in, obj);
return true;
}
return false;
}
template <class T>
bool Save(const char fileName[], T obj) {
if (ofstream out{fileName, ios::out | ios::binary}) {
to_binary(out, obj);
return true;
}
return false;
}
对于 POD 数据类型,from_binary
和 to_binary
将执行您在 Load
/Store
中已经执行的操作(但是请注意:指针是 PODs 但保存地址几乎没有意义):
template <class T, typename = enable_if_t<is_pod_v<T>>>
void from_binary(ifstream& in, T& obj) {
in.read(reinterpret_cast<char*>(addressof(obj)), sizeof(obj));
}
template <class T, typename = enable_if_t<is_pod_v<T>>>
void to_binary(ofstream& out, T const& obj) {
out.write(reinterpret_cast<char const*>(addressof(obj)), sizeof(obj));
}
正如评论中指出的那样,std::string
不是 POD 类型。我将通过保存字符数然后保存实际字符来序列化它:
void from_binary(ifstream& in, string& str) {
std::size_t stringSize{0};
from_binary(in, stringSize);
str.reserve(stringSize);
for (size_t i = 0; i != stringSize; ++i) {
char ch{};
in.read(&ch, 1);
str.push_back(ch);
}
}
void to_binary(ofstream& out, string const& str) {
auto const stringSize = str.size();
to_binary(out, stringSize);
auto const* cStr = str.c_str();
out.write(cStr, stringSize);
}
此外,我将通过对数组的每个元素调用 to_binary
/from_binary
来 serialize/deserialize 一个数组:
template <class T, size_t N>
void from_binary(ifstream& in, T (&obj)[N]) {
for (auto& elem : obj) from_binary(in, elem);
}
template <class T, size_t N>
void to_binary(ofstream& out, T const (&obj)[N]) {
for (auto const& elem : obj) to_binary(out, elem);
}
上面的函数足以实现你的Contact
和Data
from_binary
和to_binary
类:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
template <class T, typename = enable_if_t<is_pod_v<T>>>
void from_binary(ifstream& in, T& obj) {
in.read(reinterpret_cast<char*>(addressof(obj)), sizeof(obj));
}
template <class T, typename = enable_if_t<is_pod_v<T>>>
void to_binary(ofstream& out, T const& obj) {
out.write(reinterpret_cast<char const*>(addressof(obj)), sizeof(obj));
}
void from_binary(ifstream& in, string& str) {
std::size_t stringSize{0};
from_binary(in, stringSize);
str.reserve(stringSize);
for (size_t i = 0; i != stringSize; ++i) {
char ch{};
in.read(&ch, 1);
str.push_back(ch);
}
}
void to_binary(ofstream& out, string const& str) {
auto const stringSize = str.size();
to_binary(out, stringSize);
auto const* cStr = str.c_str();
out.write(cStr, stringSize);
}
template <class T, size_t N>
void from_binary(ifstream& in, T (&obj)[N]) {
for (auto& elem : obj) from_binary(in, elem);
}
template <class T, size_t N>
void to_binary(ofstream& out, T const (&obj)[N]) {
for (auto const& elem : obj) to_binary(out, elem);
}
template <class C>
bool Load(const char fileName[], C& obj) {
if (ifstream in{fileName, ios::in | ios::binary}) {
from_binary(in, obj);
return true;
}
return false;
}
template <class T>
bool Save(const char fileName[], T obj) {
if (ofstream out{fileName, ios::out | ios::binary}) {
to_binary(out, obj);
return true;
}
return false;
}
class Contact {
public:
int CompareTo(Contact obj) { return 1; }
string ss;
int rollNum;
};
void from_binary(ifstream& in, Contact& obj) {
from_binary(in, obj.ss);
from_binary(in, obj.rollNum);
}
void to_binary(ofstream& out, Contact const& obj) {
to_binary(out, obj.ss);
to_binary(out, obj.rollNum);
}
class Data {
public:
Data() {}
Contact arr[10];
};
void from_binary(ifstream& in, Data& obj) { from_binary(in, obj.arr); }
void to_binary(ofstream& out, Data const& obj) { to_binary(out, obj.arr); }
int main() {
const char fileName[] = "ContactMG.dat";
{
Data data;
auto const contactCount = sizeof(data.arr) / sizeof(data.arr[0]);
for (size_t c = 0; c != contactCount; ++c) {
data.arr[c].ss = "some name " + to_string(c);
data.arr[c].rollNum = c;
}
Save(fileName, data);
}
{
Data data;
Load(fileName, data);
for (auto const& contact : data.arr)
cout << "Contact: rollNum=" << contact.rollNum
<< ", ss=" << contact.ss << '\n';
}
}
输出:
Contact: rollNum=0, ss=some name 0
Contact: rollNum=1, ss=some name 1
Contact: rollNum=2, ss=some name 2
Contact: rollNum=3, ss=some name 3
Contact: rollNum=4, ss=some name 4
Contact: rollNum=5, ss=some name 5
Contact: rollNum=6, ss=some name 6
Contact: rollNum=7, ss=some name 7
Contact: rollNum=8, ss=some name 8
Contact: rollNum=9, ss=some name 9
虽然这可能会解决您的特定问题,但随着项目的增长,from_binary
和 to_binary
所需的重载数量会迅速增加。所以我肯定会检查是否有更全面(且经过良好测试)的库解决方案。