0

如何在文件处理中使用 C++ 字符串?我创建了一个将 C++ 字符串作为其私有数据成员之一的类,但是即使我目前没有对其进行操作,并且在构造函数中使用默认值进行了初始化,在读取文件时也会出错。写入文件时没有问题。如果我改用 C 字符串,它工作正常,但我不想。有没有办法解决这个问题?

class budget 
{      
     float balance;      
     string due_name,loan_name;              //string objects
     int  year,month;     
     float due_pay,loan_given;    

     public:                 
     budget()     
     {      
          balance=0;
          month=1;        
          due_name="NO BODY";              //default values
          loan_name="SAFE";   
          year=0;             
          balance = 0;      
          due_pay=0;        
          loan_given=0;      
     }
      .
      .
      .
 };

void read_balance()                //PROBLEM AFTER ENTERING THIS FUNCTION      
{          
     system("cls");        
     budget b;     
     ifstream f1;     
     f1.open("balance.dat",ios::in|ios::binary);     
     while(f1.read((char*)&b,sizeof(b)))     
     { b.show_data();       
     }     
     system("cls");        
     cout<<"No More Records To Display!!";     
     getch();     
     f1.close();       
} 
4

3 回答 3

2

字符串是non-POD data-type. 您不能通过读/写函数读取/写入字符串。

basic_istream<charT,traits>& read(char_type* s, streamsize n);

30 效果:表现为未格式化的输入函数(如 27.7.2.3 第 1 段所述)。构造一个哨兵对象后,如果!good() 调用setstate(failbit) 可能会抛出一个异常,并返回。 否则,提取字符并将它们存储到数组的连续位置中,其第一个元素由 s.323 指定。提取并存储字符,直到发生以下任一情况: — 存储 n 个字符;— 文件结束出现在输入序列上(在这种情况下,函数调用 setstate(failbit | eofbit),这可能会抛出 ios_base::failure (27.5.5.4))。31 返回:*this。

没有什么关于,成员如何std::string放置的。查看或使用boost::serialiation. http://www.boost.org/doc/libs/1_50_0/libs/serialization/doc/index.html当然,您可以写入字符串的大小,然后写入数据,当读取 - 读取大小时,分配此大小的数组,读取此数组中的数据,然后创建字符串。但是使用boost更好。

于 2012-07-29T20:07:25.117 回答
0

解决此问题的最简单方法是不在该类中使用 C++ 字符串。计算出您将要存储的每个字符串的最大长度,并制作一个长一个字节的 char 数组(以允许使用 0 终止符)。现在您可以将该类作为二进制文件读取和写入,而无需担心序列化等。

如果您不想这样做,则不能在课堂上使用 iostream::read() 。您将需要读/写流的成员函数。这就是序列化的意义……但是您不需要boost的复杂性。基本上,您会执行以下操作:

// Read with no error checking :-S
istream& budget::read( istream& s )
{
    s.read( (char*)&balance, sizeof(balance) );
    s.read( (char*)&year, sizeof(year) );
    s.read( (char*)&month, sizeof(month) );
    s.read( (char*)&due_pay, sizeof(due_pay) );
    s.read( (char*)&loan_given, sizeof(loan_given) );

    size_t length;
    char *tempstr;

    // Read due_name
    s.read( (char*)&length, sizeof(length) );
    tempstr = new char[length];
    s.read( tempstr, length );
    due_name.assign(tempstr, length);
    delete [] tempstr;

    // Read loan_name
    s.read( (char*)&length, sizeof(length) );
    tempstr = new char[length];
    s.read( tempstr, length );
    loan_name.assign(tempstr, length);
    delete [] tempstr;

    return s;
}

ostream& budget::write( ostream& s )
{
    // etc...
}

请注意,我们首先通过写入大小值来序列化字符串,然后再写入许多字符。

于 2012-07-30T00:25:02.620 回答
0

在读取班级预算的字符串成员 (due_name,loan_name) 时,您的代码会逐字节地填充它们。虽然它对浮点数和整数有意义,但它不适用于字符串。

字符串旨在保持“无限”数量的文本,因此它们的构造函数、复制构造函数、连接等必须确保分配实际的内存来存储文本并在必要时扩展它(并在销毁时删除)。以这种方式从磁盘填充字符串将导致字符串对象内的指针无效(不指向包含文本的实际内存),实际上根本不会以这种方式读取任何文本。

于 2012-07-29T23:17:48.530 回答