C++ 二进制读取到动态字符
C++ binary reading to dynamic char
我的代码有问题,我不知道到底是什么导致了这个问题。
Source.cpp
#include "class.h"
int main()
{
Book book1("At Mountain of Madness", "H.P Lovecraft", 1936);
book1.binaryFileWrite();
book1.binaryFileRead();
Book book2("Danwych's horror", "H.P Lovecraft", 1929);
book2.binaryFileWrite();
book2.binaryFileRead();
}
#ifndef BOOK_BINARY_LIBRARY
#define BOOK_BINARY_LIBRARY
#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
class Book
{
public:
Book()
: _year(0)
{
_title = new char[10];
_author = new char[10];
strcpy(_title, "Undefined");
strcpy(_author, "Undefined");
}
Book(const char *title, const char *author, int year)
: _year(year)
{
_titleLen = strlen(title);
_authorLen = strlen(author);
_title = new char[_titleLen + 1];
_author = new char[_authorLen + 1];
strcpy(_title, title);
strcpy(_author, author);
}
Book(const Book& book)
{
_titleLen = strlen(book._title);
_authorLen = strlen(book._author);
_title = new char[_titleLen + 1];
_author = new char[_authorLen + 1];
strcpy(_title, book._title);
strcpy(_author, book._author);
}
~Book()
{
delete[] _title;
delete[] _author;
}
void display()
{
std::cout << _title << " " << _author << " " << _year << std::endl;
}
void binaryFileWrite(const std::string &fileName = "binaryLibrary.bin")
{
std::ofstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(1);
}
else {
/*file.write(_title, sizeof(_title));
file.write(_author, sizeof(_author));
file.write(reinterpret_cast<char*>(&_year), sizeof(int));*/
file.write(reinterpret_cast<char*>(this), sizeof(Book));
}
file.close();
}
void binaryFileRead(const std::string& fileName = "binaryLibrary.bin")
{
std::ifstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(2);
}
else {
Book read;
file.read(reinterpret_cast<char*>(&read), sizeof(Book));
std::cout << read._title << " " << read._author << " " << read._year << std::endl;
}
file.close();
}
private:
char* _title;
char* _author;
int _year{ 0 };
int _titleLen{ 0 };
int _authorLen{ 0 };
};
#endif
问题肯定出在这部分代码:
void binaryFileRead(const std::string& fileName = "binaryLibrary.bin")
{
std::ifstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(2);
}
else {
Book read;
file.read(reinterpret_cast<char*>(&read), sizeof(Book));
std::cout << read._title << " " << read._author << " " << read._year << std::endl;
}
file.close();
}
它甚至打印了我想要控制台应用程序的内容,但仍然没有 return 0.
我不知道是什么问题,我试了很多都没有帮助,我什至认为它无法从 .bin
文件读取到动态字符或其他东西。
顺便说一句,我的第一个原型没有使用动态数组,我使用了固定大小的数组,如 _title[50]
和 _author[50]
,并且工作正常。我会说完美,但是当我尝试使用动态数组时它失败了。
file.write(reinterpret_cast<char*>(this), sizeof(Book));
sizeof(Book)
计算 Book
对象的大小。它是一个编译时常量值。这意味着您将始终获得 sizeof(Book)
的相同结果。您的 Book
对象包含两个 char
指针和三个 int
。在 64 位平台上,此 Book
对象的长度应为 40 个字节,而 sizeof(Book)
将为 40 个字节,并且上述 write
语句将始终尝试将恰好 40 个字符写入文件。
总是。
这两个char *
是指向空字符串,还是指向哈利波特小说的全部内容都没有关系。您将始终将 40 个字节写入文件,其中将包括这两个 char *
碰巧拥有的一对原始内存地址。当然,将原始指针值写入文件是完全没有意义的,不会产生任何有用的结果。
读取文件时也是如此。
您将需要以其他方式重新实现读取或写入文件的整个逻辑。也许首先写入所有整数值,然后是每个字符串的长度(以字节为单位),然后是每个字符串。当你读回它时,你需要实现相反的逻辑。你不需要完全那样做,你可以自由设计任何适合你的 serialization/deserialization 格式(正如它所说的),但你不能 read
和 write
一个带有指针或非平凡成员的对象,收工吧。不幸的是,C++ 并没有那么简单。
主要问题是 Book
包含 指向存储在内存中其他地方的数据的指针 。当您 read/write 按原样 Book
对象时,您 reading/writing 那些指针原样,而不是它们指向的数据。因此,您需要单独处理 char*
数据。
此外,您的 binaryFileRead()
甚至没有读入调用它的 Book
对象,它正在读入一个单独的临时 Book
对象。
试试这个:
void binaryFileWrite(const std::string &fileName = "binaryLibrary.bin")
{
std::ofstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(1); // TODO: throw an exception instead...
}
binaryWrite(file);
}
void binaryWrite(std::ostream &out)
{
out.write(reinterpret_cast<char*>(&_titleLen), sizeof(_titleLen));
out.write(_title, _titleLen);
out.write(reinterpret_cast<char*>(&_authorLen), sizeof(_authorLen));
out.write(_author, _authorLen);
out.write(reinterpret_cast<char*>(&_year), sizeof(_year));
}
void binaryFileRead(const std::string& fileName = "binaryLibrary.bin")
{
std::ifstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(2); // TODO: throw an exception instead...
}
binaryRead(file);
}
void binaryRead(std::istream &in)
{
int len;
in.read(reinterpret_cast<char*>(&len), sizeof(_len));
char *s = new char[len + 1];
in.read(s, len);
delete[] _title; _title = s;
_titleLen = len;
in.read(reinterpret_cast<char*>(&len), sizeof(_len));
s = new char[len + 1];
in.read(s, len);
delete[] _author; _author = s;
_authorLen = len;
in.read(reinterpret_cast<char*>(&_year), sizeof(_year));
}
附带说明一下,您的代码还有其他问题:
您的默认构造函数未初始化 _titleLen
和 _authorLen
字段。您真的应该考虑对 _title
和 _author
字段使用 std::string
,而不是使用 char*
+int
。特别是因为您在代码的其他地方使用 std::string
。
您的复制构造函数没有复制 _year
字段。
您的 Book
class 不符合 Rule of 3,因为它缺少复制赋值运算符。
如果将 _title
和 _author
字段切换为 std::string
,则不需要实现复制构造函数、复制赋值运算符或析构函数,因为默认的编译器生成的就足够了。
我的代码有问题,我不知道到底是什么导致了这个问题。
Source.cpp
#include "class.h"
int main()
{
Book book1("At Mountain of Madness", "H.P Lovecraft", 1936);
book1.binaryFileWrite();
book1.binaryFileRead();
Book book2("Danwych's horror", "H.P Lovecraft", 1929);
book2.binaryFileWrite();
book2.binaryFileRead();
}
#ifndef BOOK_BINARY_LIBRARY
#define BOOK_BINARY_LIBRARY
#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
class Book
{
public:
Book()
: _year(0)
{
_title = new char[10];
_author = new char[10];
strcpy(_title, "Undefined");
strcpy(_author, "Undefined");
}
Book(const char *title, const char *author, int year)
: _year(year)
{
_titleLen = strlen(title);
_authorLen = strlen(author);
_title = new char[_titleLen + 1];
_author = new char[_authorLen + 1];
strcpy(_title, title);
strcpy(_author, author);
}
Book(const Book& book)
{
_titleLen = strlen(book._title);
_authorLen = strlen(book._author);
_title = new char[_titleLen + 1];
_author = new char[_authorLen + 1];
strcpy(_title, book._title);
strcpy(_author, book._author);
}
~Book()
{
delete[] _title;
delete[] _author;
}
void display()
{
std::cout << _title << " " << _author << " " << _year << std::endl;
}
void binaryFileWrite(const std::string &fileName = "binaryLibrary.bin")
{
std::ofstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(1);
}
else {
/*file.write(_title, sizeof(_title));
file.write(_author, sizeof(_author));
file.write(reinterpret_cast<char*>(&_year), sizeof(int));*/
file.write(reinterpret_cast<char*>(this), sizeof(Book));
}
file.close();
}
void binaryFileRead(const std::string& fileName = "binaryLibrary.bin")
{
std::ifstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(2);
}
else {
Book read;
file.read(reinterpret_cast<char*>(&read), sizeof(Book));
std::cout << read._title << " " << read._author << " " << read._year << std::endl;
}
file.close();
}
private:
char* _title;
char* _author;
int _year{ 0 };
int _titleLen{ 0 };
int _authorLen{ 0 };
};
#endif
问题肯定出在这部分代码:
void binaryFileRead(const std::string& fileName = "binaryLibrary.bin")
{
std::ifstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(2);
}
else {
Book read;
file.read(reinterpret_cast<char*>(&read), sizeof(Book));
std::cout << read._title << " " << read._author << " " << read._year << std::endl;
}
file.close();
}
它甚至打印了我想要控制台应用程序的内容,但仍然没有 return 0.
我不知道是什么问题,我试了很多都没有帮助,我什至认为它无法从 .bin
文件读取到动态字符或其他东西。
顺便说一句,我的第一个原型没有使用动态数组,我使用了固定大小的数组,如 _title[50]
和 _author[50]
,并且工作正常。我会说完美,但是当我尝试使用动态数组时它失败了。
file.write(reinterpret_cast<char*>(this), sizeof(Book));
sizeof(Book)
计算 Book
对象的大小。它是一个编译时常量值。这意味着您将始终获得 sizeof(Book)
的相同结果。您的 Book
对象包含两个 char
指针和三个 int
。在 64 位平台上,此 Book
对象的长度应为 40 个字节,而 sizeof(Book)
将为 40 个字节,并且上述 write
语句将始终尝试将恰好 40 个字符写入文件。
总是。
这两个char *
是指向空字符串,还是指向哈利波特小说的全部内容都没有关系。您将始终将 40 个字节写入文件,其中将包括这两个 char *
碰巧拥有的一对原始内存地址。当然,将原始指针值写入文件是完全没有意义的,不会产生任何有用的结果。
读取文件时也是如此。
您将需要以其他方式重新实现读取或写入文件的整个逻辑。也许首先写入所有整数值,然后是每个字符串的长度(以字节为单位),然后是每个字符串。当你读回它时,你需要实现相反的逻辑。你不需要完全那样做,你可以自由设计任何适合你的 serialization/deserialization 格式(正如它所说的),但你不能 read
和 write
一个带有指针或非平凡成员的对象,收工吧。不幸的是,C++ 并没有那么简单。
主要问题是 Book
包含 指向存储在内存中其他地方的数据的指针 。当您 read/write 按原样 Book
对象时,您 reading/writing 那些指针原样,而不是它们指向的数据。因此,您需要单独处理 char*
数据。
此外,您的 binaryFileRead()
甚至没有读入调用它的 Book
对象,它正在读入一个单独的临时 Book
对象。
试试这个:
void binaryFileWrite(const std::string &fileName = "binaryLibrary.bin")
{
std::ofstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(1); // TODO: throw an exception instead...
}
binaryWrite(file);
}
void binaryWrite(std::ostream &out)
{
out.write(reinterpret_cast<char*>(&_titleLen), sizeof(_titleLen));
out.write(_title, _titleLen);
out.write(reinterpret_cast<char*>(&_authorLen), sizeof(_authorLen));
out.write(_author, _authorLen);
out.write(reinterpret_cast<char*>(&_year), sizeof(_year));
}
void binaryFileRead(const std::string& fileName = "binaryLibrary.bin")
{
std::ifstream file(fileName, std::ios::binary);
if (!file.is_open()) {
std::cout << "Failed" << std::endl;
exit(2); // TODO: throw an exception instead...
}
binaryRead(file);
}
void binaryRead(std::istream &in)
{
int len;
in.read(reinterpret_cast<char*>(&len), sizeof(_len));
char *s = new char[len + 1];
in.read(s, len);
delete[] _title; _title = s;
_titleLen = len;
in.read(reinterpret_cast<char*>(&len), sizeof(_len));
s = new char[len + 1];
in.read(s, len);
delete[] _author; _author = s;
_authorLen = len;
in.read(reinterpret_cast<char*>(&_year), sizeof(_year));
}
附带说明一下,您的代码还有其他问题:
您的默认构造函数未初始化
_titleLen
和_authorLen
字段。您真的应该考虑对_title
和_author
字段使用std::string
,而不是使用char*
+int
。特别是因为您在代码的其他地方使用std::string
。您的复制构造函数没有复制
_year
字段。您的
Book
class 不符合 Rule of 3,因为它缺少复制赋值运算符。如果将
_title
和_author
字段切换为std::string
,则不需要实现复制构造函数、复制赋值运算符或析构函数,因为默认的编译器生成的就足够了。