двоичное чтение/запись произвольного std::vector‹std::vector‹int› › в c++

Здравствуйте, я хочу сохранить двоичный объект std::vector<std::vector<int> > MATRIX в файле.

out.write((char*)&MATRIX, sizeof(MATRIX));

Проблема в том, что фиксируется только размер столбца. Изменится размер строки. Если я читаю объект из бинарного файла, то недостаточно знать только размер, не так ли? Итак, инициализация, например. вторая матрица с

std::vector<std::vector<int> > MATRIX2;
for ( int i=0;i<column_dim;i++ ) MATRIX2.push_back ( vector<int> ( 0 ) );
ifstream in(cstr, ios::in | ios::binary);

и чтение данных объекта с помощью

ifstream in(cstr, ios::in | ios::binary);    
in.read((char*)& MATRIX2, fSize);

не имеет смысла, потому что компилятор понятия не имеет о структуре сохраняемых данных. Мой вопрос: есть ли лучший способ решить эту проблему, чем сохранить матричную структуру (всю информацию о размерах строк) во втором файле, прочитать ее и создать MATRIX2 с соответствующей структурой, которая затем заполняется с помощью

ifstream in(cstr, ios::in | ios::binary);    
in.read((char*)&nn_H_test, fSize);

?


person pawel_winzig    schedule 27.05.2011    source источник
comment
Формат файла указан? Если нет, возможно, вам стоит взглянуть на boost. org/doc/libs/1_46_1/libs/serialization/doc/index.html. Это должно облегчить вам хранение и загрузку матрицы int.   -  person mkaes    schedule 27.05.2011
comment
Расширьте протокол, который я предложил в stackoverflow.com/questions/3438132/ добавьте еще один size_t перед каждой сохраненной матрицей, чтобы указать первое измерение.   -  person bobah    schedule 27.05.2011
comment
Ой, вы пытаетесь сделать дамп необработанного std::vector файла? Это никогда не сработает, и, читая его обратно, вы получите объект в полностью запутанном состоянии (единственным правильным может быть размер вектора, но внутренний указатель на элементы будет недействительным) . Вам нужна правильная сериализация.   -  person Matteo Italia    schedule 27.05.2011
comment
Это никогда не сработает, это неправда. Если я сгенерирую объект MATRIX2 с той же структурой, что и MATRIX, все будет скопировано в правильном порядке.   -  person pawel_winzig    schedule 27.05.2011
comment
вам просто повезло, в общем случае сброс std::vector в такой файл приведет к сбросу его частных членов, которые обычно представляют собой размер вектора, емкость вектора и указатель на используемую память этим. Таким образом, если вы выгружаете и перезагружаете его во время того же выполнения, он может работать, но если вы попытаетесь загрузить его в новом процессе, вы получите недопустимый внутренний указатель.   -  person Matteo Italia    schedule 28.05.2011


Ответы (3)


Я приведу краткий пример того, как это сделать с помощью . увеличить.

#include <iostream>
#include <fstream>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

std::vector<std::vector<int > > g_matrix;
int main(int argc, char* argv[])
{
    // fill the vector
    std::ofstream ofs("c:\\dump");
    boost::archive::text_oarchive to(ofs);
    to << g_matrix;

    g_matrix.clear();
    std::ifstream ifs("c:\\dump");
    boost::archive::text_iarchive infs(ifs);
    infs >> g_matrix;
    // check your vector. It should be the same
}

Если вам нужно, чтобы он был более удобочитаемым, вы также можете попробовать xml из boost.
Как всегда, не изобретайте велосипед.

person mkaes    schedule 27.05.2011

ios::binary почти определенно НЕ будет иметь результат, который, как вы думаете, будет иметь - это влияет только на перевод конца строки.

Во-вторых, вам не избежать необходимости сохранять отдельные длины внутренних векторов, если вы хотите восстановить структуру при чтении. Восстановление необработанного std::vector из потока непосредственно в новый std::vector, как вы пытаетесь сделать сейчас, никогда не сработает.

Однако структурированное восстановление не должно быть сложным, просто сохраните количество значений, а затем все значения для каждого внутреннего вектора. Затем ваша подпрограмма чтения может безопасно прочитать первое значение, затем прочитать N следующих значений и предположить, что первое значение после этого является количеством значений следующей строки.

person Joris Timmermans    schedule 27.05.2011
comment
Спасибо за комментарий. На ваше первое замечание: что бы вы предложили вместо этого? - person pawel_winzig; 27.05.2011
comment
Если вы хотите сохранить вектор как истинные двоичные данные (например, используя 4 байта на диске для 4-байтового целого числа), вам следует рассмотреть возможность записи пользовательского потока двоичного файла с использованием чтения и записи потока. - person Joris Timmermans; 27.05.2011

Для чего-то очень простого, почему бы просто не поместить значение заголовка перед выводом матрицы, указывающее размер столбца строки? Тривиальный пример:

4,2 //#rows, #columns
0 1
2 0
2 3
4 5

Теперь, когда вы читаете матрицу, читайте информацию заголовка, а затем данные матрицы.

Если вы хотите, чтобы матрица была сериализуемой, вам следует рассмотреть парадигму сериализации для вашей матричной структуры. Подробнее о сериализации читайте в часто задаваемых вопросах по C++.

person nathan    schedule 27.05.2011
comment
Спасибо, да, это тоже первое, что пришло мне в голову, но у него есть недостаток: некоторые из моих алгоритмов уже используют эту матрицу, мне пришлось бы их переписать — к сожалению, это потребует больше работы, чем добавление дополнительного файла. - person pawel_winzig; 27.05.2011
comment
Если это проблема, то сериализация, вероятно, ваше решение. Таким образом, все это содержится в матрице. - person nathan; 27.05.2011