如何从/向二进制文件读取/写入std :: string值

Cha*_*han 3 c++

我想将一个Item写入二进制文件,关闭它,然后再打开它来读取它.代码简单明了,使用Visual Studio 2008编译和运行时没有错误.

但是,当使用GCC编译器运行时,它会出现"段错误".

我究竟做错了什么?

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class Item
{
private:
    string itemID;
    string itemName;
    string itemState;

public:
    Item( const string& id = "i0000", const string& name = "Zero item", const string& state = "not init" )
        : itemID( id ) , itemName( name ) , itemState( state )
    {

    }

    string& operator []( int x )
    {
        if ( 0 == x )
            return itemID;
        if ( 1 == x )
            return itemName;
        if ( 2 == x )
            return itemState;

        return ( string& )"";
    }

    const string& operator []( int x ) const
    {
        if ( 0 == x )
            return itemID;
        if ( 1 == x )
            return itemName;
        if ( 2 == x )
            return itemState;

        return ( string& )"";
    }

public:
    friend istream& operator >>( istream& i, Item& rhs )
    {
        cout << " * ItemID: ";
        getline( i, rhs.itemID );
        cout << " - Item Name: ";
        getline( i, rhs.itemName );
        cout << " - Item State: ";
        getline( i, rhs.itemState );
        return i;
    }

    friend ostream& operator <<( ostream& o, const Item& rhs )
    {
        return o << "ID = " << rhs.itemID
                 << "\nName = " << rhs.itemName
                 << "\nState = " << rhs.itemState << endl;
    }
};

void write_to_file( const string& fn, const Item& item )
{
    fstream outf( fn.c_str(), ios::binary | ios::out );
    Item temp( item );
    outf.write( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
    outf.close();
}

void read_from_file( const string& fn, Item& item )
{
    fstream inf( fn.c_str(), ios::binary | ios::in );

    if( !inf )
    {
        cout << "What's wrong?";
    }
    Item temp;
    inf.read( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
    item = temp;
    inf.close();
}

int main()
{
    string fn = "a.out";
    //Item it( "12", "Ipad", "Good" );
    //write_to_file( fn, it );


    Item temp;
    read_from_file( fn, temp );
    cout << temp;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

And*_*ron 8

这两行:

outf.write( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
Run Code Online (Sandbox Code Playgroud)

inf.read( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
Run Code Online (Sandbox Code Playgroud)

错了.您正在编写对象的二进制布局,包括std::string实例.这意味着您正在编写指向文件的指针值并将其读回.

你不能简单地从文件中读取指针并假设它们指向有效的内存,特别是如果它由一个临时std::string实例保存,当它超出范围时应该释放它的析构函数中的内存.我很惊讶你用任何编译器"正确"运行它.

你的程序应该写的内容和使用读回operator<<operator>>方法.它应该如下所示:

void write_to_file( const string& fn, const Item& item )
{
    fstream outf( fn.c_str(), ios::binary | ios::out );
    outf << item << std::endl;
    outf.close();
}

void read_from_file( const string& fn, Item& item )
{
    fstream inf( fn.c_str(), ios::binary | ios::in );
    if( !inf )
    {
        cout << "What's wrong?";
    }
    inf >> item;
    inf.close();
}
Run Code Online (Sandbox Code Playgroud)

奖励:您的代码有一些怪癖.

幸运的是,这个陈述目前在您的程序中未使用(该方法未被调用).

return ( string& )"";
Run Code Online (Sandbox Code Playgroud)

它无效,因为您将返回对临时字符串对象的引用.记住,字符串文字""不是一个std::string对象,你不能得到它的类型的引用std::string&.你应该提出异常,但你可以逃脱:

string& operator []( int x )
{
    static string unknown;
    if ( 0 == x )
        return itemID;
    if ( 1 == x )
        return itemName;
    if ( 2 == x )
        return itemState;
    return unkonwn;
}
Run Code Online (Sandbox Code Playgroud)

考虑到字符串是通过引用返回的,这是一个很差的解决方案.它可以被调用者修改,因此它可能不会总是返回""您认为的值.但是,它将删除程序的未定义行为.

对象的.close()方法调用std::fstream不是必需的,当对象超出范围时,析构函数会自动调用它.插入呼叫会有额外的混乱.

另外,冗余命名约定是什么?

class Item
{
private:
    string itemID;
    string itemName;
    string itemState;
// ...
};
Run Code Online (Sandbox Code Playgroud)

出了什么问题打电话给他们ID,namestate