Важнейшим вопросом является то, как вы планируете получить доступ к файлу: последовательный или произвольный доступ?
последовательного доступа (вроде) или нескольких данных
Каков наилучший способ определения каждого объекта в файле. Например, в текстовом файле я мог бы разделить каждый объект с символом новой строки. Этот подход подходит и для двоичных файлов?
Очевидно нет ;-). Но не волнуйтесь, есть лучшее решение. Чтобы сохранить список данных, можно просто и буквально сохранить 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.
Спасибо за объяснение. Моим вариантом использования является последовательный доступ. Однако вместо того, чтобы поддерживать индексный файл, я думаю, что было бы лучше хранить размеры записей вместе с записями. Например, первые 4 байта каждой записи будут указывать количество байтов, составляющих запись (при условии, что запись не превышает 4 ГБ). Таким образом, абсолютные смещения не нужно сохранять, а также облегчать вставку/удаление. – jithinpt
Просто предположим, что ваш файл данных охватывает несколько ГБ и спрашивает себя: поиск, вставка или удаление записи в индексе '15.883.127' из' 124.657.013' записей - это задача «O (1)» или, по крайней мере, 'O (logN) 'с использованием этого алгоритма? Помните, что ** почти все алгоритмы бывают быстрыми, если у вас есть только 10 элементов данных. **. – JensG
Если вы все еще хотите это сделать, посмотрите на 'TFramedProtocol'. Он делает именно это и записывает размер кадра данных, который следует за i32 в выходной поток. – JensG