将结构写入二进制文件后,该文件仍然具有普通字符,而不是不可读的字符 [英] After writing a structure into a binary file, the file still has normal characters instead of unreadable ones
问题描述
我正在尝试将结构写入二进制文件.该结构由字符串和整数组成.如果没有字符串,我只是将整个对象带入正常情况下将其写入二进制文件,但是如果现在执行该操作,则也可以轻松读取字符串.
I'm trying to write a structure to a binary file. The structure consists of strings and integers. If there were no strings I'd just take the entire object and write it to the binary file normally, but if I do that now, the string can be read easily as well.
因此,我决定分别编写该结构的每个属性.我正在使用这些字符串,就像在Stackoverflow答案中提到的一样.
So I decided to write each of the attribute of the structure separately. I was working with the strings the same way like it's mentioned in this Stackoverflow answer.
这是应该将结构保存到 name.bin 文件中的主要功能.
This is the main function that is supposed to save the structure into the name.bin file.
void saveFileBin(std::string nameOfFile) {
Person people[SIZE_OF_ARRAY] =
{Person("Name1", "lastName2", Address("Street1", "City1", "111"), Date(1, 1, 1111)),
Person("Name2", "lastName2", Address("Street2", "City2", "222"), Date(2, 2, 2222)),
Person("Name3", "lastName3", Address("Street3", "City3", "333"), Date(3, 3, 3333))};
std::ofstream myFile(nameOfFile + ".bin", std::ios::binary);
if (myFile.is_open())
{
for (int i = 0; i < SIZE_OF_ARRAY; i++)
{
people[i].write(&myFile);
}
myFile.close();
std::cout << "The entire thing is in memory";
}
else
{
throw std::exception("Unable to open file");
}
};
这是用于将每个属性写入文件的功能.
and this is a function for writing each attribute into the file.
void Person::write(std::ofstream* out)
{
out->write(_name.c_str(), _name.size());
out->write(_lastName.c_str(), _lastName.size());
out->write(_residence.getStreet().c_str(), _residence.getStreet().size());
out->write(_residence.getZip().c_str(), _residence.getZip().size());
out->write(_residence.getCity().c_str(), _residence.getCity().size());
std::string day = std::to_string(_birthDate.getDay());
std::string month = std::to_string(_birthDate.getMonth());
std::string year = std::to_string(_birthDate.getYear());
out->write(day.c_str(), day.size());
out->write(month.c_str(), month.size());
out->write(year.c_str(), year.size());
}
生成的文件具有纯文本可读的所有内容.尽管如果我改为在主方法中调用 myFile.write((char *)people,sizeof(people));
,它会正确显示无法读取的字符,但仍可以正常读取字符串变量.这就是为什么我将所有变量都转换为字符串,然后将其完全写入bin文件的原因.
The resulting file has everything in plain text readable.
Though if I instead in the main method call myFile.write((char*)people, sizeof(people));
then it shows up unreadable characters correctly but string variables are still normally read. That's why I went with converting into the string all variables and then writing it to a bin file altogether.
为什么我的方法仍然显示所有字符串,甚至不是二进制文件?即使我将std :: ios :: binary作为参数?
How come my method still shows all strings like it's not even binary file? Even though I have std::ios::binary as a parameter?
输出文件包含以下内容:
The output file contains this:
Name1lastName1Street11111City11111111Name2lastName2Street22222City22222222Name3lastName3Street33333City3333333
如果我将整个结构写到二进制文件中,则看起来像这样:
Whereas if I write the entire structure into the binary file, it looks like this:
lÊ87 Name1 ÌÌÌÌÌÌÌÌÌÌ à^Ê87 lastName1 ÌÌÌÌÌÌ Ð_Ê87 Street1 ÌÌÌÌÌÌÌÌ ÐdÊ87 City1 ÌÌÌÌÌÌÌÌÌÌ bÊ87 111 ÌÌÌÌÌÌÌÌÌÌÌÌ W ÌÌÌÌ`kÊ87 Name2 ÌÌÌÌÌÌÌÌÌÌ fÊ87 lastName2 ÌÌÌÌÌÌ €iÊ87 Street2 ÌÌÌÌÌÌÌÌ PbÊ87 City2 ÌÌÌÌÌÌÌÌÌÌ ÐiÊ87 222 ÌÌÌÌÌÌÌÌÌÌÌÌ ® ÌÌÌÌ€dÊ87 Name3 ÌÌÌÌÌÌÌÌÌÌ `Ê87 lastName3 ÌÌÌÌÌÌ p`Ê87 Street3 ÌÌÌÌÌÌÌÌ gÊ87 City3 ÌÌÌÌÌÌÌÌÌÌ ðbÊ87 333 ÌÌÌÌÌÌÌÌÌÌÌÌ
ÌÌÌÌ lÊ87 Name1 ÌÌÌÌÌÌÌÌÌÌ à^Ê87 lastName1 ÌÌÌÌÌÌ Ð_Ê87 Street1 ÌÌÌÌÌÌÌÌ ÐdÊ87 City1 ÌÌÌÌÌÌÌÌÌÌ bÊ87 111 ÌÌÌÌÌÌÌÌÌÌÌÌ W ÌÌÌÌ`kÊ87 Name2 ÌÌÌÌÌÌÌÌÌÌ fÊ87 lastName2 ÌÌÌÌÌÌ €iÊ87 Street2 ÌÌÌÌÌÌÌÌ PbÊ87 City2 ÌÌÌÌÌÌÌÌÌÌ ÐiÊ87 222 ÌÌÌÌÌÌÌÌÌÌÌÌ ® ÌÌÌÌ€dÊ87 Name3 ÌÌÌÌÌÌÌÌÌÌ `Ê87 lastName3 ÌÌÌÌÌÌ p`Ê87 Street3 ÌÌÌÌÌÌÌÌ gÊ87 City3 ÌÌÌÌÌÌÌÌÌÌ ðbÊ87 333 ÌÌÌÌÌÌÌÌÌÌÌÌ
ÌÌÌÌ lÊ87 Name1 ÌÌÌÌÌÌÌÌÌÌ à^Ê87 lastName1 ÌÌÌÌÌÌ Ð_Ê87 Street1 ÌÌÌÌÌÌÌÌ ÐdÊ87 City1 ÌÌÌÌÌÌÌÌÌÌ bÊ87 111 ÌÌÌÌÌÌÌÌÌÌÌÌ W ÌÌÌÌ`kÊ87 Name2 ÌÌÌÌÌÌÌÌÌÌ fÊ87 lastName2 ÌÌÌÌÌÌ €iÊ87 Street2 ÌÌÌÌÌÌÌÌ PbÊ87 City2 ÌÌÌÌÌÌÌÌÌÌ ÐiÊ87 222 ÌÌÌÌÌÌÌÌÌÌÌÌ ® ÌÌÌÌ€dÊ87 Name3 ÌÌÌÌÌÌÌÌÌÌ `Ê87 lastName3 ÌÌÌÌÌÌ p`Ê87 Street3 ÌÌÌÌÌÌÌÌ gÊ87 City3 ÌÌÌÌÌÌÌÌÌÌ ðbÊ87 333 ÌÌÌÌÌÌÌÌÌÌÌÌ
ÌÌÌÌ
根据要求,这里是Person.h的标头
As requested here is a header for Person.h
#pragma once
#ifndef PERSON_H
#define PERSON_H
#include <string.h>
#include "Address.h"
#include "Date.h"
#include <fstream>
struct Person {
public:
Person(std::string name, std::string last_name, Address _residence, Date birthDate);
Person();
friend std::ostream& operator<<(std::ostream& os, const Person& p);
friend std::istream& operator>>(std::istream& is, Person& p);
std::string getName() const { return _name; }
std::string getLastName() const { return _lastName; };
Address getResidence() const { return _residence; };
Date getDate() const { return _birthDate; };
void read(std::ifstream *in);
void write(std::ofstream *out);
private:
std::string _name;
std::string _lastName;
Address _residence;
Date _birthDate;
};
#endif // !PERSON_H
推荐答案
用于序列化 std :: string
(长度限制为≤ 65536个字符)的示例:
A sample to serialize a std::string
(with a limited length of ≤ 65536 characters):
#include <cassert>
#include <iostream>
#include <fstream>
void writeString(std::ostream &out, const std::string &str)
{
// write length of string (two bytes, little endian)
assert(str.size() <= 1 << 16);
const size_t size = str.size();
char buffer[2] = { (char)(size & 0xff), (char)(size >> 8 & 0xff) };
out.write(buffer, sizeof buffer)
// write string contents
&& out.write(str.c_str(), size);
}
void readString(std::istream &in, std::string &str)
{
// read length
char buffer[2];
if (!in.read(buffer, 2)) return; // failed
const size_t size = (unsigned char)buffer[0] | (unsigned char)buffer[1] << 8;
// allocate size
str.resize(size);
// read contents
in.read(&str[0], size);
}
int main()
{
// sample
std::string name = "Antrophy";
// write binary file
{ std::ofstream out("test.dat", std::ios::binary);
writeString(out, name);
} // closes file
// reset sample
name = "";
// read binary file
{ std::ifstream in("test.dat", std::ios::binary);
readString(in, name);
} // closes file
// report result
std::cout << "name: '" << name << "'\n";
}
输出:
name: 'Antrophy'
test.dat
的十六进制转储:
00000000 08 00 41 6e 74 72 6f 70 68 79 |..Antrophy|
0000000a
注意:
考虑如何写长度(限制为16位).可以像序列化整数值一样进行此操作.
Consider how the length (limited to 16 bit) is written. This can be done similar to serialize integral values.
C ++ FAQ提供了一个(IMHO)很好的介绍:
A (IMHO) good introduction is provided by the C++FAQ:
组合类型为 Person
的二进制I/O的扩展示例:
An extended sample for binary I/O of a composed type Person
:
#include <cassert>
#include <iostream>
#include <fstream>
template <size_t nBytes, typename VALUE>
std::ostream& writeInt(std::ostream &out, VALUE value)
{
const size_t size = sizeof value;
char buffer[nBytes];
const size_t n = std::min(nBytes, size);
for (size_t i = 0; i < n; ++i) {
buffer[i] = (char)(value >> 8 * i & 0xff);
}
for (size_t i = size; i < nBytes; ++i) buffer[i] = '\0';
return out.write(buffer, nBytes);
}
template <size_t nBytes, typename VALUE>
std::istream& readInt(std::istream &in, VALUE &value)
{
const size_t size = sizeof value;
char buffer[nBytes];
if (in.read(buffer, nBytes)) {
value = (VALUE)0;
const size_t n = std::min(nBytes, size);
for (size_t i = 0; i < n; ++i) {
value |= (VALUE)(unsigned char)buffer[i] << 8 * i;
}
}
return in;
}
void writeString(std::ostream &out, const std::string &str)
{
// write length of string (two bytes, little endian)
assert(str.size() <= 1 << 16);
const size_t size = str.size();
writeInt<2>(out, size)
// write string contents
&& out.write(str.c_str(), size);
}
void readString(std::istream &in, std::string &str)
{
// read length
std::uint16_t size = 0;
if (!readInt<2>(in, size)) return; // failed
// allocate size
str.resize(size);
// read contents
in.read(&str[0], size);
}
struct Person {
std::string lastName, firstName;
int age;
void write(std::ostream&) const;
void read(std::istream&);
};
void Person::write(std::ostream &out) const
{
writeString(out, lastName);
writeString(out, firstName);
writeInt<2>(out, age);
}
void Person::read(std::istream &in)
{
readString(in, lastName);
readString(in, firstName);
std::int16_t age; assert(sizeof age == 2); // ensure proper sign extension
if (readInt<2>(in, age)) this->age = age;
}
int main()
{
// sample
Person people[2] = {
{ "Mustermann", "Klaus", 23 },
{ "Doe", "John", -111 }
};
// write binary file
{ std::ofstream out("test.dat", std::ios::binary);
for (const Person &person : people) person.write(out);
} // closes file
// read sample
Person peopleIn[2] = {
{ "", "", -1 },
{ "", "", -1 }
};
// read binary file
{ std::ifstream in("test.dat", std::ios::binary);
for (Person &person : peopleIn) person.read(in);
} // closes file
// report result
int i = 1;
for (const Person &person : peopleIn) {
std::cout << "person " << i++ << ": '"
<< person.firstName << ' ' << person.lastName
<< ", age: " << person.age << '\n';
}
}
输出:
person 1: 'Klaus Mustermann, age: 23
person 2: 'John Doe, age: -111
test.dat
的十六进制转储:
00000000 0a 00 4d 75 73 74 65 72 6d 61 6e 6e 05 00 4b 6c |..Mustermann..Kl|
00000010 61 75 73 17 00 03 00 44 6f 65 04 00 4a 6f 68 6e |aus....Doe..John|
00000020 91 ff |..|
00000022
注意:
与简单的 out.write()相比,整数值(
在其他位置找到.我以一种更加可移植的方式完成了该操作,甚至可以在具有不同字节序和/或不同积分大小的不同平台上使用. readInt()
和 writeInt()
)的二进制I/O可能看起来过于复杂.(char *)value,sizeof value);
The kind of binary I/O for integral values (readInt()
and writeInt()
) might look overcomplicated compared to the simple out.write((char*)value, sizeof value);
found elsewhere. I did it in a more portable way which will even work when used on different platforms with distinct endianess and/or distinct size of integrals.
这篇关于将结构写入二进制文件后,该文件仍然具有普通字符,而不是不可读的字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!