2015-06-03 3 views
0

Я хочу, чтобы иметь возможность записывать связанный список типа Music в двоичный файл, а затем читать его обратно в связанный список. Конечно, у меня проблемы с этим. Насколько я понимаю, моя проблема в том, что строка является переменной длиной. Поскольку строка не всегда одинакового размера, при чтении ее не видно, сколько нужно читать. Я собирался преобразовать свой класс в фиксированные длины cstrings, чтобы исправить проблему. Фактически, я пытался, но имел несколько других проблем, которые были вызваны этим. Мой вопрос: есть ли способ сделать то, что я хочу, без кардинального изменения моего кода?Чтение двоичного файла в объект класса

void ReadBinFile(Node * head, string filename) 
{ 
    Music new_song; 
    ifstream bin(filename, ios::in | ios::binary); 
    if (bin.is_open()) 
    { 
     while (!bin.eof()) 
     { 
      bin.read(reinterpret_cast<char *>(&new_song), sizeof(Music)); 
      if (!bin.eof()) 
      { 
       Node * new_node = CreateNode(new_song); 
       AppendNode(head, new_node); 
      } 
     } 
     bin.close(); 
    } 
} 
void Save(Node * head, string filename) 
{ 
    ofstream bin(filename, ios::out | ios::binary); 
    if (bin.is_open()) 
    { 
     Node * traveler = head; 
     while (traveler != nullptr) 
     { 
      bin.write(reinterpret_cast<char *>(&(traveler->song)), sizeof(Music)); 
      traveler = traveler->next; 
     } 
     bin.close(); 
    } 
} 
Node * CreateNode(Music song) 
{ 
    Node * new_node = new Node; 
    new_node->song = song; 
    new_node->next = nullptr; 

    return new_node; 
} 
//music.h 
class Music 
{ 
    public: 
     Music(string name = "", string artist = ""); 

    private: 
     string m_name; 
     string m_artist; 
}; 
+0

Хотите добавить информацию о том, как выглядит формат вашего двоичного файла? –

+0

@CyberSpock Я бы, но я точно не знаю, что это за формат. Я не знаю много о бинарных файлах. Я мог бы скопировать + вставить пример одного сгенерированного, если это поможет. –

+0

вам нужно сначала определить формат, а затем создать функции pack/unpack для чтения/записи одной записи. –

ответ

1

Делать, как это

bin.read(reinterpret_cast<char *>(&new_song), sizeof(Music)); 

не закончится хорошо, если вы посмотрите на класс Music

class Music 
{ 
    public: 
     Music(string name = "", string artist = ""); 

    private: 
     string m_name; 
     string m_artist; 
    ... 

чтения просто перезаписать строки, которые не принимают во внимание строковый шаблон.

Чтобы справиться с этим перегружать ПОТОКОВЫЙ операторы >> и <<, так что вы можете в коде чтение из файла, как это:

... 
Music song; 
bin >> song; 
... 

Для этого добавьте вне ваших функций Музыки класса, чтобы упаковать и распаковать экземпляр ,

E.g.

std::ostream& operator<<(std::ostream& out, const Music &in) 
{ 
    return out << in.m_name.length() << in.m_name.c_str() 
     << in.m_artist.length() << in.m_artist.c_str(); 
} 

std::istream& operator>>(std::istream& is, Music &in) 
{ 
    // pseudo code 
    // read length, read characters of name put into "in" 
    // read length, read characters of artist put into "in" 
} 

Внутри этих функций вы преобразовали бы в бинарный формат по вашему выбору. Двоичный файл - это просто данные, которые интерпретируются необработанным способом и не сильно отличаются от текстового файла, который также является двоичным файлом, за исключением того, что один принимает определенный формат, например. читаемые символы и, возможно, символы новой строки.

Если вы хотите сохранить в двоичной форме, вам нужно выяснить способ хранения достаточной информации, чтобы вы могли получить ее позже. например если вы храните строку, вы можете либо сохранить длину строки сначала, либо символы после нее, либо сохранить строку и иметь окончание \ 0 в конце, чтобы вы знали, когда остановиться при чтении строки.

+0

Спасибо! Я собираюсь прочитать это и попробовать все, когда у меня найдется время. –

+0

рад, что я мог бы помочь, удачи! –

1

К сожалению, вы используете строки, которые являются классами самостоятельно (с динамически назначенной длиной). Если вы хотите написать целый класс, он должен быть постоянным размером, но даже тогда я бы не рекомендовал его.

Добавить методы чтения и записи в класс и прочитать/написать каждое поле на своем собственном.


В разъяснении:
Вы хотите изменить музыку так:
class Music { public: Music(string name = "", string artist = ""); void Write(std::string filename); void Read(str::string filename); private: string m_name; string m_artist; };
Затем вы можете открыть файл в двоичном режиме и написать имя, а затем написать художник:
size_t len = str.size();
вы пишете длину строка
file.write(reinterpret_cast<const char*>(&len), sizeof(len));
затем записать фактическую строку данных:
file.write(str.c_str(), len);


И тогда вы читаете то же самое -> сначала читаете размер, затем читаете, что много символов;)
Он немного изменит ваш код, но я думаю, что это был бы правильный способ сделать это.

+0

Спасибо! Я не думал, что все будет так просто. Я попробую, когда у меня будет время. Возможно, вы избавили меня от стресса. –

+0

Просто сообщите нам, если какое-либо решение сработало для вас;) – MKK

Смежные вопросы