Сброс памяти в файл - PullRequest
       0

Сброс памяти в файл

6 голосов
/ 12 октября 2010

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

Как правильно это сделать?

Моя первая мысль была:

char* start = my_pointer;
int i;
for (i = 0; i < MEMORY_SIZE; i++) {
    // write *start to file
    start++;
}

Могу ли я написать все это как символы? А затем используйте что-то вроде этого, чтобы восстановить его в памяти.

//loop
    *my_pointer = fgetc(f);
    my_pointer++;

Будут ли мои "структуры данных" выживать как "персонажи", или мне нужно будет записать их в каком-нибудь бинарном / гекса-режиме данных? Или это стандартный способ сделать это?

Ответы [ 5 ]

10 голосов
/ 12 октября 2010

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

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

Это может варьироваться от сохранения в качестве форматов файлов, использования баз данных, преобразования в XML или другой иерархический формат и так далее. То, что является правильным решением, полностью зависит от того, какие у вас есть данные и какие операции вы над ними выполняете, а также от того, как часто вы планируете записывать, а затем читать с диска. (Или сеть. Или что вы делаете.)

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

fwrite(my_pointer, MEMORY_SIZE, 1, fp);

, а затем fread () , чтобы прочитать данные обратно. Также см. Связанный (более или менее связанный, в зависимости от того, насколько продвинуты ваши потребности) вопрос о сериализации в StackOverflow .

Правильная сериализация также решает проблемы, возникающие , когда предполагается, что разные типы процессоров могут считывать данные друг с друга. Правильная сериализация в Си намного сложнее, чем в других языках. Например, в Лиспе все данные и код уже сериализованы. В Java есть методы, которые помогут вам сериализовать ваши данные. Свойства C, делающие его подходящим языком для высокопроизводительного и системного программирования, также затрудняют его использование для некоторых других вещей.

2 голосов
/ 12 октября 2010

Пока данные, которые вы выгружаете, не содержат указателей, просто их выгрузка будет работать.(СОВЕТ: используйте вызовы, которые могут записывать длинные последовательности данных за один раз, чтобы сократить время.) Единственное, на что нужно обратить внимание, это если вы пишете целые числа или числа с плавающей запятой и читаете их обратно на машине сдругая архитектура (например, big endian вместо little endian).Это может или не может беспокоить вас.

Но если у вас есть указатели внутри, у вас есть проблема.Проблема в том, что вы не можете (ну, не можете легко) гарантировать, что вы загрузите данные обратно в ту же позицию в пространстве виртуальной памяти принимающего процесса.Более того, если у вас есть данные, которые имеют указатели на то, что вы не сохраняете (например, блуждающий FILE*), то вам нужно подумать о том, что нужно сделать, чтобы повторно синтезировать действительную замену в этой точке.Такая сериализация крайне нетривиальна и требует написания кода, который точно знает, что вы сохраняете и загружаете.

Существует способ немного упростить сериализацию, когда у вас есть только указатели в смежныхДанные сохраняются и всегда собираются восстановить на одной архитектуре.Извлеките память, как и раньше, но добавьте префиксный дескриптор, который говорит, по крайней мере, о длине данных и количестве указателей внутри, затем также сохраните (в конце) таблицу того, где именно (как смещения в данных)указатели и где начало всех данных было.Затем вы можете восстановить данные путем считывания данных и выполнения адресной арифметики для исправления всех указателей, т. Е. Вы можете определить, какое смещение относительно начала исходных данных, на которые они указывали, - как char*, а не как исходный тип.- и убедитесь, что они указывают на одно и то же смещение относительно адреса целых данных после перезагрузки.Это довольно грубый взлом и формально не самая переносимая вещь в истории, но в рамках ограничений, изложенных в начале этого параграфа, я ожидаю, что это сработает.Однако у вас также будет действительно непереносимый формат сериализации; не рассчитывайте на это вообще для любого вида постоянного архивного использования!

2 голосов
/ 12 октября 2010

Вы можете использовать

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

функция.

ptr - pointer to you memory segment.
size - size of memory to write.
stream - file you writing to.

Будут ли мои "структуры данных" выживать как "персонажи", или мне нужно будет записать их в каком-нибудь бинарном / гекса-режиме данных? Или это стандартный способ сделать это?

при открытии файла - используйте символ 'b' в параметре "mode"

2 голосов
/ 12 октября 2010

Если вы используете систему unixy style, memmap и memcpy могут дать вам правильное решение.

1 голос
/ 12 октября 2010

Правильный способ сделать это - использовать библиотеку сериализации.

То, действительно ли вам это нужно, зависит от сложности ваших данных. Если данные, которые вам нужно записать, не содержат каких-либо указателей, то вы можете просто использовать fwrite для записи данных и fread для их считывания. Просто убедитесь, что вы открыли файл с данные в двоичном режиме.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...