Запись в начале файла того, что вы знаете только в конце

9

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

Когда я могу сохранить весь элемент EBML в памяти, генерировать его легко, потому что я могу вернуться и заполнить длину каждого элемента после того, как узнаю, что это за длина. Проблема в том, что делать, когда я не могу удержать весь элемент в памяти. Варианты, которые я вижу:

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

Вопрос: Похоже, это должно быть относительно распространенной проблемой, о которой думали люди. Я знаю, что это также может произойти при формировании некоторых пакетов данных. Есть ли здесь лучшая / более распространенная / более приемлемая техника, которую я пропускаю? Или просто некоторые термины для вопроса, который я могу найти?

pscheidler
источник
1
/ sccs работает следующим образом: он записывает контрольную сумму всех байтов в начале файла после того, как завершит запись. Прекрасно работает на Unix, которые могут выполнять необходимые файловые операции атомарно (например, Solaris), и вызывает странные спорадические проблемы в Unix, которые не могут этого сделать, например, Linux
gnat

Ответы:

2

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

Просто запишите «неизвестный размер».

Эта функция зависит от полезной нагрузки, состоящей из элементов EBML и следующего элемента, который не является допустимым дочерним элементом.

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


За подробностями обращайтесь к проекту EBML RFC на matroska.org.

Deduplicator
источник
Это замечательно! Это то, о чем я не знал, и это позволяет избежать основной проблемы, но я все же хотел бы получить руководство по хорошему способу решения основной проблемы. Использование элемента неизвестного размера может ограничить совместимость в будущем, поскольку старое программное обеспечение преждевременно завершит работу с новыми элементами.
pscheidler
Вам нужен правильный DTD, или вы не можете реально декодировать EBML. Ну, если все неизвестные элементы имеют размеры, вы можете их пропустить, но достаточно ли этого? Просто обработайте любой EBML, который вы хотите хранить в автономном режиме, если он есть.
Дедупликатор
Мы используем нашу собственную схему, которая будет расширяться. Он был разработан с учетом того, что старое программное обеспечение может в конечном итоге пропустить некоторые данные. Но это отличная особенность EBML, о которой я не знал, поэтому я принимаю ответ.
pscheidler
0

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

Для последовательностей вы можете попытаться определить максимальное количество подэлементов и «поток», оставшихся в следующем файле

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

В общем постарайтесь минимизировать количество слишком больших элементов

Whoot
источник
Ну, он мог бы сделать это для своих собственных элементов EBML, но это все равно не помогает ему с родительским элементом.
Дедупликатор
Ваша идея будет работать, но я бы предпочел создать систему, которая может обрабатывать большие элементы, вместо того, чтобы ограничивать схему, чтобы избежать крупных элементов.
pscheidler
Это решение будет работать и для больших элементов, просто будьте осторожны с размером стека. И если речь идет о схеме ... воспринимайте ее как язык, используемый вашими приложениями, если один не может справиться со сложным, то другой должен настроить, или требуется переводчик. Многие разработчики (по крайней мере, те C / C ++, которых я знаю) склонны избегать изменений схемы / дизайна, как будто это был пожар, который позже приводит к плохой системе. Если другой компонент не может быть отрегулирован, возможно, он плохо разложен / спроектирован. Если есть другие причины, по которым не нужно вносить изменения, вам следует рассмотреть возможность использования другого оборудования
Whoot
0

ПОЦЕЛУЙ и ЯГНИ.
Выберите вариант № 1, и если это станет реальной проблемой - только затем повторите это.

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

Kromster
источник