C++ 将结构写入二进制文件后,该文件仍然具有普通字符,而不是无法读取的字符
我正在尝试将结构写入二进制文件。结构由字符串和整数组成。如果没有字符串,我只需要将整个对象正常地写入二进制文件,但是如果我现在这样做,字符串也可以很容易地读取 所以我决定分别编写结构的每个属性。我在用琴弦演奏 这是将结构保存到name.bin文件中的主要功能C++ 将结构写入二进制文件后,该文件仍然具有普通字符,而不是无法读取的字符,c++,binaryfiles,binary-data,file-writing,C++,Binaryfiles,Binary Data,File Writing,我正在尝试将结构写入二进制文件。结构由字符串和整数组成。如果没有字符串,我只需要将整个对象正常地写入二进制文件,但是如果我现在这样做,字符串也可以很容易地读取 所以我决定分别编写结构的每个属性。我在用琴弦演奏 这是将结构保存到name.bin文件中的主要功能 void saveFileBin(std::string nameOfFile){ 人物[数组的大小]= {个人(“姓名1”、“姓氏2”、地址(“街道1”、“城市1”、“111”)、日期(1111年1月1日), 此人(“姓名2”、“姓氏2”
void saveFileBin(std::string nameOfFile){
人物[数组的大小]=
{个人(“姓名1”、“姓氏2”、地址(“街道1”、“城市1”、“111”)、日期(1111年1月1日),
此人(“姓名2”、“姓氏2”、地址(“街道2”、“城市2”、“222”)、日期(2、2、2222)),
个人(“姓名3”、“姓氏3”、地址(“街道3”、“城市3”、“333”)、日期(3333);
std::ofstreammyfile(nameOfFile+“.bin”,std::ios::binary);
如果(myFile.is_open())
{
for(int i=0;i<数组的大小;i++)
{
人员[i]。编写(&myFile);
}
myFile.close();
std::cout 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文件
为什么我的方法仍然显示所有字符串,就像它不是二进制文件一样?即使我有std::ios::binary作为参数
输出文件包含以下内容:
Name1lastName1Street11111City11111111Name2lastName2Street22222City22222222Name3lastName3Street33333City3333333
而如果我将整个结构写入二进制文件,它看起来是这样的:
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的标题
#pragma一次
#ifndef人员
#定义人
#包括
#包括“Address.h”
#包括“Date.h”
#包括
结构人{
公众:
人员(std::string name、std::string姓氏、地址、住所、出生日期);
人();
friend std::ostream&operator(std::istream&is,Person&p);
std::string getName()常量{return\u name;}
std::string getLastName()常量{return\u lastName;};
地址getResidence()const{return\u residence;};
Date getDate()常量{return\u birthDate;};
无效读取(标准::ifstream*in);
无效写入(std::ofstream*out);
私人:
std::string _name;
std::string _lastName;
地址(香港);;
日期-出生日期;
};
#endif//!PERSON_H
序列化std::string
(长度限制为≤ 65536个字符):
test.dat的hextump
:
00000000 08 00 41 6e 74 72 6f 70 68 79 |…无齿|
0000000 A
注意:
考虑如何写入长度(限制为16位)。这可以类似于序列化整数值
C++常见问题解答提供了(IMHO)良好的介绍:
组合类型的二进制I/O的扩展示例
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';
}
}
test.dat的hextump
:
00000000 0a 00 4d 75 73 74 65 72 6d 61 6e 6e 05 00 4b 6c |吉隆坡穆斯特曼|
00000010617573170000300446F6504004A 6F686E | aus…Doe…John|
000000 20 91 ff||
00000022
注意:
整型值(
readInt()
和writeInt()
)的二进制I/O类型与简单的out.write((char*)值,sizeof值)相比可能过于复杂
可在其他地方找到。我采用了一种更便携的方式,即使在不同的平台上使用不同的尾数和/或不同的整数大小时也能工作。字符a
内部由其ASCII码65表示。将字符串写入二进制文件,字符串的字节将被写入。使用文本编辑查看或者,在这个二进制文件中,字节将再次被解释为字符,即值为65的字节再次成为A
。不管你认为二进制是什么,它只是二进制,但没有加密。查看.exe
文件。即使在那里,你也会发现一些可读文本的部分(可能)。顺便说一句out->write(_name.c_str(),_name.size());
覆盖所有字符,但不覆盖字符串的结尾处。请写入_name.size()+1
以捕获0终止符,或者在字符串前面加上写入长度的前缀(二进制)。二进制文件并不表示“加密”顺便说一句,你能提供Person类的声明吗?我怀疑你写的是((char*)人,sizeof(people))不向文件写入任何字符串,只向them@Antrophy然而,如果我将整个结构写入二进制文件——让我们看看结构。正如前面的评论所述,如果Person
不可复制,那么就不应该写入二进制文件。@Antrophy——这就解决了——你不能写入Person
到那样的二进制文件。您的类不是POD或可复制的。还要从逻辑上考虑一下——您可能在编写代码时使用了sizeof(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';
}
}