Как записать вектор в файл c

Обновлено: 07.07.2024

Спасибо Матсу Петерссону за объяснение того, как скопировать вектор в массив, это похоже на работу. Вот фрагмент кода:

Но я гость, этот метод будет тратить огромную память и быть громоздким. Может быть, я подумаю над тем, чтобы написать г-ну с оцелотом и другими предложениями. Спасибо всем за ответ.

4 ответа

Вы пишете в файл векторную структуру, а не ее буфер данных. Попробуйте изменить процедуру записи на:

И вместо того, чтобы вычислять размер вектора по размеру файла, лучше написать размер вектора (количество объектов) раньше. В этом случае вы можете записать в тот же файл другие данные.

Чтобы сохранить vector<T> из POD в файле, вы должны записать содержимое вектора, а не сам вектор. Вы можете получить доступ к необработанным данным с помощью &vector[0] , адреса первого элемента (если он содержит хотя бы один элемент). Чтобы получить длину необработанных данных, умножьте количество элементов в векторе на размер одного элемента:

То же самое относится и к чтению вектора из файла; Количество элементов - это общий размер файла, деленный на размер одного элемента. (учитывая, что в файле хранится только один тип POD):

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

Кроме того, при переносе числовых типов в двоичном виде между различными системами следует учитывать endianness .

Скорее всего, вы не можете писать в двоичном (как вы делаете) какие-либо std::vector , потому что этот шаблон содержит внутренние указатели, а также запись и повтор читать их бессмысленно.

Некоторые общие советы:

не записывайте в двоичном виде какие-либо контейнеры шаблонов STL (например, std::vector или std::map ), они наверняка содержат внутренние указатели, которые вы действительно не хотите писать как есть. Если вам действительно нужно написать их, реализуйте свои собственные процедуры записи и чтения (например, с использованием итераторов STL).

избегайте использования strcpy без осторожности. Ваш код будет сбой, если имя содержит более 30 символов. По крайней мере, используйте strncpy(m_name, name, sizeof(m_name)); (но даже это будет плохо работать для имени из 30 символов). На самом деле m_name должно быть std::string .

явно сериализует ваши контейнерные классы (обрабатывая каждый значащий элемент данных). Вы можете использовать JSON нотацию (или, возможно, YAML , или, может быть, даже XML - который я считаю слишком сложным, поэтому не рекомендую) сериализовать. Он дает вам текстовый формат дампа, который вы можете легко проверить с помощью стандартного редактора (например, emacs или gedit ). Вы найдете много сериализации бесплатных библиотек, например, jsoncpp и многие другие.

научитесь компилировать с g++ -Wall -g и использовать gdb отладчик и valgrind детектор утечки памяти; также научитесь использовать make и написать свой Makefile -s.

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

Для функций read () и write () вам нужно то, что называется «обычные старые данные» или «POD». В основном это означает, что класс или структура не должны иметь указателей внутри и виртуальных функций. Реализация вектора, безусловно, имеет указатели - я не уверен насчет виртуальных функций.

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

Причина, по которой вы не можете записывать данные не POD, в частности указатели, в двоичный файл, заключается в том, что при повторном чтении данных вы почти наверняка можете поспорить, что структура памяти изменилась по сравнению с тем, когда вы ее записали. Это немного похоже на попытку припарковаться на том же парковочном месте в магазинах - кто-то еще припарковался на третьем месте от входа, когда вы в следующий раз явитесь, так что вам придется выбрать другое место. Подумайте о памяти, выделенной компилятором как места для парковки, а информацию о студентах - как автомобили.

[Технически, в этом случае, это еще хуже - ваш вектор на самом деле не содержит учеников внутри класса, что вы и записываете в файл, поэтому вы даже не сохранили информацию об учениках, только информация о том, где они находятся (количество парковочных мест)]

Быстрый переход по статье:

Что такое вектор (vector)

Как создать вектор (vector) в C++

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

Далее, чтобы объявить вектор, нужно пользоваться конструкцией ниже:

  • Вначале пишем слово vector .
  • Далее в угольных скобках указываем тип, которым будем заполнять ячейки.
  • И в самом конце указываем имя вектора.

В примере выше мы создали вектор строк.

После имени вектора ставим знак равенства и скобки, в которых через пробел указываем значение элементов.

Такой способ инициализации можно использовать только в C++!

Второй способ обратиться к ячейке

Мы знаем, что в векторе для обращения к ячейке используются индексы. Обычно мы их используем совместно с квадратными скобками [] .

Вот как она работает на практике:

ivector . at ( 1 ) = 5 ; // изменили значение второго элемента

Давайте запустим эту программу:

Как указать количество ячеек для вектора

Указывать размер вектора можно по-разному. Можно это сделать еще при его инициализации, а можно хоть в самом конце программы. Вот, например, способ указать длину вектора на старте:

Так в круглых скобках () после имени вектора указываем первоначальную длину. А вот второй способ:

cout << "Значения второго вектора (с помощью reserve): " << endl ;

Как видим, в первом случае мы вывели три нуля, а во втором: 17, 0, 0.

Все потому, что при использовании первого способа все ячейки автоматически заполнились нулями.

При объявлении чего-либо (массива, вектора, переменной и т.д) мы выделяем определенное количество ячеек памяти, в которых уже хранится ненужный для ПК мусор. В нашем случае этим мусором являются числа.


Как сравнить два вектора

Если в середине программы нам понадобиться сравнить два массива, мы, конечно, используем цикл for и поочередно проверим все элементы.

Вектор снова на шаг впереди! Чтобы нам сравнить два вектора, потребуется применить всего лишь оператор ветвления if.

Спасибо Матсу Петерссону за объяснение того, как скопировать вектор в массив, это, кажется, работает. Вот код снипета:

Но я думаю, что этот метод будет тратить огромную память и будет громоздким. Может быть, я подумаю о том, чтобы написать его вместе с оцелотом и другими предложениями. Спасибо всем за ответ.

4 ответа

У меня есть массив long . Как записать этот массив в двоичный файл? Проблема в том, что если я преобразую его в массив byte , то некоторые значения изменяются. Массив похож на: long array = new long[160000]; Дайте какой-нибудь фрагмент кода.

все! У меня есть вектор 2D, заполненный неподписанными символами. Теперь я хочу сохранить его содержимое в двоичный файл: std::vector<std::vector<unsigned char> > v2D(1920, std::vector<unsigned char>(1080)); // Populate the 2D vector here . FILE* fpOut; // Open for write if (.

Чтобы сохранить vector<T> из PODs в файле, вы должны записать содержимое вектора, а не сам вектор. Вы можете получить доступ к необработанным данным с &vector[0] , адресом первого элемента (если он содержит хотя бы один элемент). Чтобы получить длину необработанных данных, умножьте количество элементов в векторе на размер одного элемента:

То же самое относится и к чтению вектора из файла; Количество элементов-это общий размер файла, деленный на размер одного элемента (учитывая, что в файле хранится только один тип POD):

Это работает только в том случае, если вы можете рассчитать количество элементов на основе размера файла (если вы храните только один тип POD или если все векторы содержат одинаковое количество элементов). Если у вас есть векторы с разными PODs с разной длиной, вы должны записать количество элементов в векторе в файл перед записью необработанных данных.

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

Вы пишете в файл векторную структуру, а не ее буфер данных. Попробуйте изменить процедуру записи на:

И вместо того, чтобы вычислять размер вектора из размера файла, лучше написать размер вектора (количество объектов) раньше. В этом случае вы можете записать в тот же файл другие данные.

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

Некоторые общие советы:

не пишите в двоичном формате никакие контейнеры шаблонов STL (например, std::vector или std::map ), они наверняка содержат внутренние указатели, которые вы действительно не хотите писать как есть. Если вам действительно нужно их написать, реализуйте свои собственные процедуры записи и чтения (например, используя итераторы STL).

избегайте использования strcpy без осторожности. Ваш код выйдет из строя, если имя содержит более 30 символов. По крайней мере, используйте strncpy(m_name, name, sizeof(m_name)); (но даже это будет плохо работать для имени из 30 символов). На самом деле m_name должно быть std::string .

сериализуйте явно свои классы контейнеров (обрабатывая каждый значимый член данных). Вы могли бы рассмотреть возможность использования обозначения JSON (или , возможно , YAML, или, может быть, даже XML-что я нахожу слишком сложным, поэтому не рекомендую) для сериализации. Это дает вам текстовый формат дампа, который вы можете легко проверить с помощью стандартного редактора (например, emacs или gedit ). Вы найдете множество бесплатных библиотек сериализации, например, jsoncpp и многие другие.

научитесь компилировать с g++ -Wall -g и использовать отладчик gdb и детектор утечки памяти valgrind ; также научитесь использовать make и писать свои Makefile -ы.

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

Мне нужно записать список int в двоичный файл длиной 4 байта , поэтому мне нужно убедиться, что двоичный файл правильный, и я делаю следующее: using (FileStream fileStream = new FileStream(binaryFileName, FileMode.Create)) // destiny file directory. < using (BinaryWriter binaryWriter = new.

Я должен записать приведенный ниже двоичный массив в файл: byte[] data = new byte[] < 0x55, 0xAA, 0x02>; Я хочу поместить точные данные в файл (55,AA,02). Пожалуйста, дайте мне знать, как это сделать.

Для функций read() и write() вам нужно то, что называется "plain old data" или "POD". Это в основном означает, что класс или структура не должны иметь внутри себя указателей и виртуальных функций. реализация вектора, безусловно, имеет указатели - я не уверен в виртуальных функциях.

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

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

[Технически, в этом случае все еще хуже - ваш вектор на самом деле не содержит учеников внутри класса, что вы и записываете в файл, поэтому вы даже не сохранили информацию о студентах, а только информацию о том, где они находятся (количество парковочных мест)]

Похожие вопросы:

У меня есть очень простые, но огромные векторы: struct Vectors //of the same types and the same sizes < vector<int> A; vector<int> B; vector<int> C; vector<int> D;.

как записать ArrayList в двоичный файл? допустим, у меня есть arraylist под названием people я пытаюсь записать это в двоичный файл с помощью метода writeListToBinary мой метод: public void.

Возможный дубликат : использование bash: запись битового представления целого числа в файл Мне нужно записать размер файла в двоичный файл. Например: $ stat -c %s in.txt 68187 $ stat -c %s in.txt.

У меня есть массив long . Как записать этот массив в двоичный файл? Проблема в том, что если я преобразую его в массив byte , то некоторые значения изменяются. Массив похож на: long array = new.

все! У меня есть вектор 2D, заполненный неподписанными символами. Теперь я хочу сохранить его содержимое в двоичный файл: std::vector<std::vector<unsigned char> > v2D(1920.

Мне нужно записать список int в двоичный файл длиной 4 байта , поэтому мне нужно убедиться, что двоичный файл правильный, и я делаю следующее: using (FileStream fileStream = new.

Я должен записать приведенный ниже двоичный массив в файл: byte[] data = new byte[] < 0x55, 0xAA, 0x02>; Я хочу поместить точные данные в файл (55,AA,02). Пожалуйста, дайте мне знать, как это.

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

Я пытаюсь записать char[] в двоичный файл, это мой метод, для int, float, double и char* friend ofstream& operator<<(ofstream& outB, Test& t) < //scriem int, float si double normal.

Spritz

14 декабря 2011 г. 14:45, спустя 2 минуты 33 секунды

You can be anything you want to be. Just turn yourself into anything you think that you could ever be.

Spritz

14 декабря 2011 г. 14:49, спустя 4 минуты 22 секунды

интересно, кроме boost-а можно отдельно найти имплементацию сериализации…?

Spritz

14 декабря 2011 г. 14:52, спустя 3 минуты 2 секунды

You can be anything you want to be. Just turn yourself into anything you think that you could ever be.

Spritz

14 декабря 2011 г. 14:56, спустя 3 минуты 40 секунд

Spritz

14 декабря 2011 г. 17:41, спустя 2 часа 45 минут 14 секунд

Spritz

14 декабря 2011 г. 22:20, спустя 4 часа 38 минут 52 секунды

Пипец, буст только ради сериализации?
Проблема не в том, что std неправильно работает, а том, что ты сам непонимаешь того, что ты делаешь.

Блеать, сделайте меня это разувидеть. Пральна хуярим в файл целиком структуру данных с указателями, а затем считываем и надеемся что в заданных адресах памяти будут лежать именно нужные нам данные =)

Spritz

14 декабря 2011 г. 22:52, спустя 31 минуту 38 секунд

Nyaah, насколько я понял, в приведенном выше примере в файл записывается только адрес вектора :D You can be anything you want to be. Just turn yourself into anything you think that you could ever be.

Spritz

14 декабря 2011 г. 22:55, спустя 2 минуты 44 секунды

не, мне кажется vD всё таки вектор, а не указатель на вектор

Spritz

14 декабря 2011 г. 23:52, спустя 57 минут 2 секунды

Nyaah, как бы ты записал в файл данный вектор с структурами без сериализации?
подскажи? …Frozzeg- функции передаётся адрес первого элемента из вектора.
Nyaah- ни std а stl ;)
вообще-то можно только нужный компонент использовать из либы ;)
и вообще ещё буст использовал для создания потоков(многопоточности), так что уж извиняйте- велосипеды не по мне

Spritz

15 декабря 2011 г. 10:27, спустя 10 часов 35 минут 29 секунд

Nyaah, как бы ты записал в файл данный вектор с структурами без сериализации?

Последовательно записать все элементы в файл не судьба? Только не так же, как ты вектор записывал, а поочерёдно все поля, друг за дружкой в определённом порядке.

…Frozzeg- функции передаётся адрес первого элемента из вектора.

Я же говорю не понимаешь, что делаешь…
vector<Dis> !== Dis[length], это абсолютно разные вещи, и &vD - это не первый элемент вектора, это адрес самого вектора.

Вот ни всё ли равно.

и вообще ещё буст использовал для создания потоков(многопоточности), так что уж извиняйте- велосипеды не по мне
Да бля, просто скажи, что не знаешь как поток новый создать

Spritz

15 декабря 2011 г. 18:23, спустя 7 часов 55 минут 59 секунд

Последовательно записать все элементы в файл не судьба? Только не так же, как ты вектор записывал, а поочерёдно все поля, друг за дружкой в определённом порядке.
Я же говорю не понимаешь, что делаешь…
vector<Dis> !== Dis[length], это абсолютно разные вещи, и &vD - это не первый элемент вектора, это адрес самого вектора.
Да бля, просто скажи, что не знаешь как поток новый создать

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

Spritz

15 декабря 2011 г. 20:09, спустя 1 час 45 минут 38 секунд

бегин я незаметил, сорри, но он возвращает итератор, а не массив, ты все равно не прав )
И да я не против буста, он охуенен, так же как и qt, так же как флекс в ас3, но меня просто нервирует, когда неразорбравшись даже в азах начинают их использовать.

Spritz

18 декабря 2011 г. 11:55, спустя 2 дня 15 часов 46 минут

… нервный ты какой-то…

зы я и не писал что begin возвращает массив )… ну внимательность это отдельная тема…

а азы, что же подразумевается под этим? (для тебя)

Кстати, так и не был предложен метод записи без буста?…

Spritz

18 декабря 2011 г. 19:41, спустя 7 часов 45 минут 54 секунды

Это после работы, так как полторы недели ипался с админкой на флексе, которая была паписана хер знает как недавно уволенным программистом. Вот он тоже не гладя в мануал херачил все данные в эррей коллекшены, не думая совершенно, нужны емы эвенты, не нужны… Херня, что у менеджеров, для которых все это писалось дохлые компики на атомах, и при загрузке сотни другой записей все начинает дико тормозить. А проблема оказалась именно в том, что ArrayCollection во флексе расширяет эвент диспатчер и при любом чихе, коллекция срёт кучей эвентов в очередо событий, как оказалось Vector в экшен скрипте на два где-то порядка шустрее работает, вот я эту куйню перелопачивал, а ты под горячую руку вместе с бустом попал, не принимай близко к сердцу xD
Азы это понимание как работает си с памятью - человек должен понимать, что std::vector.begin() - это итератор, то есть объект который внутрях своих где-то ссылается на сам вектор, либо на массив данных в векторе, в зависимости от реализации, что манипулировать с ним это манипулировать только одним единственным элементом. Что функция fwrite принимает первым аргументом указатель на область памяти, из которой будет скопированы данные в файл, и что если тебе нужно задампить массив данных, то нужно передвать указатель именно на массив.
Использование буста для сериализации не самый плохой метод, но ты знаешь как он работает? Ты уверен в том, что после того как ты в структуре Dis поля местами поменяешь, либо добавишь новое свойство, у тебя старые сериализованные файлы будут адекватно считываться?
По поводу записи, был пердложен метод, но ту его телегой обозвал ) Если ты пишешь приложение не только для себя, то он на мой взгляд единственно верный, при условии что нужно именно в файл писать. Если не обязательно лить данные в файл, я бы подумал не писать ли их в бд. Запись последовательно в определённом формате (который ты собственно сам должен придумать), с указанием сигнатуры текущей версии файла, гарантирует тебе:
а) отсутствие оверхеда
б) в будущем отсутствие гемора с обратной совместимостью
в) ты точно будешь знать как что работает, а не так, что звонят девочкам в тп со словами "У меня файл не загружается в новой версии", они тебя спрашивают, что случилось, на что ты им ответишь, "а хз, сериализация в бусте так работает"

Ещё. Если пишешь на плюсах, бы ло бы неплохо юзать всётаки стримы, а не f* функции и классы вместо структур. Создаёшь класс Discipline учишь его работать с std::istream и std::ostream, после чего для записи в файл нужно будет только написать (это я так, структура файла должна быть удобочитаемой для программы, это не руководство к действию =)) что-то типа:

Читайте также: