在文件处理中使用C++字符串

Use C++ strings in file handling

本文关键字:C++ 字符串 文件 处理      更新时间:2023-10-16

如何在文件处理中使用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();       
} 

字符串为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当然,您可以写入字符串的大小,然后写入数据,当读取-读取大小时,分配这个大小的数组,读取这个数组中的数据,然后创建字符串。但使用助推更好。

在读取类预算的字符串成员(due_name,loan_name)时,代码会逐字节填充它们。虽然它对浮点和int有意义,但对字符串不起作用。

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

解决这个问题的最简单方法是不在该类中使用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...
}

请注意,我们已经通过先写一个大小值,然后再写那么多字符来序列化字符串。