2015-04-07 2 views
0

Я хочу сохранить вектор объектов в файл. Каков наиболее эффективный способ сделать это? Должен ли я загружать весь вектор при запуске программы, работать с ним локально, а затем сохранять его, когда программа выходит или получает доступ к файлу каждый раз, когда мне нужно что-то менять внутри вектора?Сохранение вектора объектов в файл в C++

Кроме того, возможно ли вообще сохранить весь вектор сразу или мне нужно сохранить элементы по одному?

+0

Что вы имеете в виду объекты? –

+0

Это зависит от того, для чего вы хотите его использовать. – zoska

+0

@ErikW, объекты класса – foofaraw

ответ

1

Если ваши данные POD (и, следовательно, каждый элемент имеет одинаковый размер), вы можете использовать следующие идеи. Если нет, следующие идеи могут быть легко использованы легко.

Следующий код показывает, что вы можете использовать «ostream :: write», чтобы вывести двоичные данные в файл. вектор <> обещает, что объекты находятся в обратном порядке (или наоборот, по вашему желанию) в памяти, поэтому они выстраиваются в линию и относительно компактны для передачи.

Чтение обратно в память аналогично, используя «istream :: read». Но здесь вам нужно выделить буферизацию 1-го.

В следующем коде я выделил 6 объектов для записи, затем нашел начало векторной памяти и написал все 6 объектов с одной «записью».

Для чтения я создавал и загружал 6 объектов в новый вектор (обратите внимание, что вектор предоставляет slicker способ выделения и создания объектов с использованием по умолчанию ctor).

Как вы передаете количество объектов от усилия записи до чтения? Это можно вычислить из размера файла. (см. стат)

Использование реинтерпрет-литья не является (как правило) приемлемым и может быть не переносимым. Но иногда вам просто нужно это делать.

Надеюсь, это «зло» подскажет ряд лучших вариантов.

Я ушел в отладку std :: cout ... надеюсь, что вы найдете их полезными.

редактировать - 4/8 - очистить код несколько

 // create a vector of 6 clear elements to save to file 
     std::vector<Something> vec6W(6); // default ctor clears contents 

     // change several elements by init'ing them 
     vec6W[0].init(); 
     // [1] is clear (all 0's) 
     vec6W[2].init(); 
     vec6W[3].init(); 
     // [4] is clear (all 0's) 
     vec6W[5].init(); 

     std::cout << "    vec6W.size(): " << vec6W.size()  << std::endl; // 6 
     std::cout << "    sizeof(vec6W): " << sizeof(vec6W)  << std::endl; // 12 
     std::cout << "   sizeof(something): " << sizeof(Something) << std::endl; // 100 
     std::cout << "   sizeof(vec6W[3]): " << sizeof(vec6W[3]) << std::endl; // 100 

     //      #elements  bytes per element 
     std::streamsize nBytes = (vec6W.size() * sizeof(Something)); 
     std::cout << "      nBytes : " << nBytes << std::endl; // 600 

     // simulate a file using 
     std::stringstream ss; 

     // note size 
     std::cout << "    ss.str().size(): " << ss.str().size() << std::endl; // 0 

     // identify address of 1st element of vector 
     // cast to a 'const char*' for 'write()' method 
     const char* wBuff = reinterpret_cast<const char*>(&vec6W[0]); 

     // report address 
     std::cout << " static_cast<const void*>(wBuff): " << std::hex 
       << static_cast<const void*>(wBuff) << std::dec << std::endl; 

     //write vector to ss 
     ss.write(wBuff, nBytes); 

     std::cout << "\n note ss content size change " << std::endl; 
     std::cout << "   ss.str().size() : " << ss.str().size() << std::endl; 

     // ////////////////////////////////////////////////////////////////// 
     // build a vector of 6 clear elements to create buffer for read from file 
     std::vector<Something> vec6R(6); 

     // identify address of 1st element of vector 
     std::cout << "     &vec6R[0] : " << std::hex << (&vec6R[0]) << std::dec << std::endl; 

     char* rBuff = reinterpret_cast<char*>(&vec6R[0]); 

     // read vector from ss 
     (void)ss.read(rBuff, nBytes); // read back same number of bytes 

     // ////////////////////////////////////////////////////////////////// 
     // confirm vec6R matches what was written vec6W 
     int diff = memcmp(wBuff, rBuff, nBytes); 

     std::cout << (diff ? "FAILED" : "wBuff MATCHES rBuff: SUCCESS") << std::endl; 

     // now consider comparing vec6R to vec6W element by element 

Там могут быть дополнительные вопросы, когда класс имеет виртуальные методы.

Удачи.

редактировать -----

Указатели могут быть обработаны, но создают дополнительную работу, а некоторые асимметрии.

Связанные работы можно назвать «стойким хранилищем».

Кроме того, существует инструменты для упрощения дополнительных шагов не-POD данных (извините, я забыл название).

+0

После небольшого исследования я понял, что сохранение всего вектора сразу станет излишним на моем уровне «программирования» и пойдет на сбор объектов один за другим и сохранит их как строки в отдельных строках файла .dat. Я определенно буду признателен за ваш ответ в моих будущих попытках. – foofaraw

1

Нет ответа на этот вопрос.

Соответствующий подход зависит от потребностей вашего приложения, почему он сохраняет файл и что будет сделано с файлом. Например, файл, который предназначен для открытия в другой программе и понятный человеку, может быть написан совершенно иначе, чем файл, который просто сохраняет состояние программы (т. Е. Что только программная программа должна это понимать).

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

Как правило, запись набора объектов включает в себя запись всех объектов по отдельности, а также некоторую дополнительную учетную запись (например, вывод количества объектов), особенно если файл необходимо прочитать позже. Однако более разумные алгоритмы могут выводить некоторые сводные данные из набора объектов. Например, предположим, что вектор, содержащий целые числа от 1 до 20 по порядку. Один из способов написания - написать все 20 значений. Другой - просто испустить строку «1-20».

+0

Спасибо за ответ @Peter Я хотел бы сохранить свои данные в виде двоичного файла. Кроме того, я буду получать доступ к данным из файла много раз за один проход, поэтому, я думаю, лучший выбор для меня - прочитать файл при запуске и записать его при выходе. Я прав? – foofaraw

+0

Ну, чтение файла один раз при запуске и запись его при завершении - один из вариантов. Однако нет единого «лучшего выбора» - есть выбор дизайна, и есть хорошие и плохие последствия для каждого выбора дизайна. Не абсолюты, как «лучшие». Также будьте осторожны с бинарными файлами - не все типы классов C++ могут выжить, будучи записаны как двоичные файлы и будут считаны. – Peter

+0

Предположим, я хочу сохранить пользовательский объект, содержащий некоторые идентификаторы, имя, пароль и т. Д. Какой тип файла следует ли использовать, если не бинарный? – foofaraw

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