2017-01-17 17 views
1

Требования
  • Мне нужно хранить поток Бережливость-сериализованных объектов в файле таким образом, что я могу прочитать файл, который в дальнейшем и получить десериализованные объекты.
  • Объекты могут быть разных типов.

Вопросы

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

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

ответ

1

Важнейшим вопросом является то, как вы планируете получить доступ к файлу: последовательный или произвольный доступ?

последовательного доступа (вроде) или нескольких данных

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

Очевидно нет ;-). Но не волнуйтесь, есть лучшее решение. Чтобы сохранить список данных, можно просто и буквально сохранить list<data>. Другими словами, что-то вроде этого:

struct foo { 1: string field, 2: i32 otherfield } 

list<foo> 

Если данные не только foo, но различного типа, поставить союз между ними:

struct foo { 1: string field, 2: i32 otherfield } 

struct bar { 1: map<string,wtf> seinfield, 2: double cloverfield } 

struct wtf { 1: list<double> even_more_fields } 

union MyDataRecord { 
    1: foo foo 
    2: bar bar 
    3: wtf wtf 
} 

list<MyDataRecord> 

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

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

Если вы поместили данные в list<>, как описано выше, Thrift позаботится об этом. Вы просто читаете и записываете весь список в целом.

произвольного доступа и/или множество данных

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

position = sizeof(foo) * index_of_desired_element 

потому что foo имеет элемент переменного размера данных: string поля.

Для решения этой проблемы у нас в основном есть два варианта.

(1) Записи фиксированного размера: Мы можем убедиться, что все элементы не превышают предопределенный максимальный размер и используют это как размер записи файла. Мы также больше не используем list<>, вместо этого мы записываем наши данные в правильные позиции в файле. Положение п-го элемента, чем снова

position = N * predefined_record_size 

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

(2) Индексный файл: Второй вариант состоит в том, чтобы поддерживать отдельный файл индекса, который содержит позицию каждой записи в файле данных. Это, опять-таки может быть простой список целых чисел:

list<i32> 

Недостатком здесь, что вам нужно, чтобы убедиться, что индекс находится в надлежащей форме, особенно при вставке, удаление и обновление операций в середине файла ,

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

Нижняя линия

Если у вас есть только куча данных, то list<union> подход может быть то, что вы ищете. Поскольку union можно продлить в любое время, решение также будет готово для добавления других элементов позже.

Если вы абсолютно хотите получить доступ к данным только последовательно, либо выберите подход list<union>, либо запишите/напишите union элементы по одному. Thrift поддерживает функцию Skip(), которая позволяет пропускать ненужные данные, если это необходимо.

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


1) Сканирование потенциально большой файл для записи разделителей не the kind of O(?) you want.

+0

Спасибо за объяснение. Моим вариантом использования является последовательный доступ. Однако вместо того, чтобы поддерживать индексный файл, я думаю, что было бы лучше хранить размеры записей вместе с записями. Например, первые 4 байта каждой записи будут указывать количество байтов, составляющих запись (при условии, что запись не превышает 4 ГБ). Таким образом, абсолютные смещения не нужно сохранять, а также облегчать вставку/удаление. – jithinpt

+0

Просто предположим, что ваш файл данных охватывает несколько ГБ и спрашивает себя: поиск, вставка или удаление записи в индексе '15.883.127' из' 124.657.013' записей - это задача «O (1)» или, по крайней мере, 'O (logN) 'с использованием этого алгоритма? Помните, что ** почти все алгоритмы бывают быстрыми, если у вас есть только 10 элементов данных. **. – JensG

+0

Если вы все еще хотите это сделать, посмотрите на 'TFramedProtocol'. Он делает именно это и записывает размер кадра данных, который следует за i32 в выходной поток. – JensG