Escrever no início de um arquivo algo que você só conhece no final


9

Antecedentes: estou escrevendo o código C do microcontrolador para gravar um arquivo EBML. A EBML é como um XML binário com elementos aninhados, mas em vez de tags de início e fim, há um ID de início, comprimento e, em seguida, os dados. Estou escrevendo isso no Flash externo em um aplicativo de baixa potência, por isso, gostaria de manter o mínimo possível o acesso ao flash. A memória também é limitada, porque nada é fácil.

Quando posso manter todo o elemento EBML na memória, é fácil gerá-lo, pois posso voltar e preencher o comprimento de cada elemento depois de saber qual é esse comprimento. O problema é o que fazer quando não consigo armazenar todo o elemento na memória. As opções que vejo são:

  • Escreva o que eu sei, depois volte e adicione os comprimentos (mais fácil, mas adiciona mais acesso ao flash do que eu quero)
  • Calcular o comprimento de cada elemento antes de começar a escrevê-lo (relativamente fácil, mas muito tempo do processador)
  • Alterne os modos assim que a memória ficar cheia, para que eu continue com os dados, mas apenas para calcular os comprimentos dos elementos já reservados na memória. Em seguida, escreva o que tenho na memória e volte e continue processando os dados de onde parei. (Minha opção favorita até agora)
  • Forneça aos elementos um comprimento máximo ou pior, quando eles precisam ser gravados e seu comprimento final ainda não é conhecido. (Mais fácil do que acima, mas pode sair pela culatra e desperdiçar espaço)

Pergunta: Parece que esse deve ser um problema relativamente comum em que as pessoas pensaram. Eu sei que isso também pode acontecer ao formar alguns pacotes de dados. Existe uma técnica melhor / mais comum / mais aceita que estou perdendo aqui? Ou apenas alguns termos para o problema que eu posso pesquisar?


11
/ sccs funciona da seguinte maneira: escreve a soma de verificação de todos os bytes no início do arquivo depois de terminar de escrever. Funciona muito bem em Unixes que pode fazer operações de arquivo necessários atomicamente (por exemplo Solaris) e causa problemas esporádicos estranhas em Unixes que não pode fazer isso, por exemplo, Linux
mosquito

Respostas:


2

Se você não souber quanto tempo sua carga útil terá, isso raramente é motivo de preocupação, mesmo que você não consiga se lembrar da posição e preencha o comprimento posteriormente:

Apenas anote "tamanho desconhecido".

Esse recurso depende da carga útil que consiste em elementos EBML e o elemento a seguir não é um elemento filho válido.

Se desejar, você pode canonizar posteriormente a EBML resultante offline, conforme sua conveniência, da maneira que desejar, por exemplo, "sem tamanhos desconhecidos, tamanho mínimo" ou "tamanho mínimo, evitar tamanhos desconhecidos".


Consulte o rascunho de RFC da EBML em matroska.org para obter detalhes.


Isso é ótimo! É algo que eu não conhecia e evita o problema principal, mas ainda assim gostaria de orientação sobre uma boa maneira de resolver o problema principal. O uso de um elemento de tamanho desconhecido parece limitar a compatibilidade futura, pois o software antigo sairia prematuramente de novos elementos.
Pscheidler

Você precisa da DTD correta ou não pode realmente decodificar a EBML. Bem, se todos os elementos desconhecidos forem dimensionados, você poderá ignorá-los, mas isso é suficiente? Apenas pós-processe qualquer EBML que você deseja armazenar offline, se for.
Deduplicator

Estamos usando nosso próprio esquema, que será expandido. Foi desenvolvido com o conhecimento de que um software mais antigo pode eventualmente ter que pular alguns dados. Mas esse é um ótimo recurso da EBML que eu desconhecia, então aceito a resposta.
Pscheidler

0

Se um único elemento com número fixo de subelementos for muito grande, talvez você deva tentar dividi-lo no esquema. Não conheço esse formato, mas provavelmente você pode definir um comprimento máximo nele.

Para seqüências, você pode tentar definir a contagem máxima de subelementos e o "fluxo" restantes no próximo arquivo

Para elementos que excedam o tamanho máximo da memória, prepare uma pilha contendo pares: localização do comprimento do elemento reservado e contador de comprimento. No pop, salve o contador atual no marcador atual e adicione seu valor ao próximo contador.

Em geral, tente minimizar o número de elementos muito grandes


Bem, ele provavelmente poderia fazer isso por seus próprios elementos EBML, mas isso ainda não o ajuda com o elemento pai.
Deduplicator

Sua idéia funcionaria, mas eu prefiro criar um sistema que possa lidar com elementos grandes, em vez de restringir o esquema para evitar elementos grandes.
Pscheidler

Essa solução também funcionará para elementos grandes, mas tenha cuidado com o tamanho da pilha. E se se trata de esquema ... pense nele como um idioma que seus aplicativos estão usando, se um não puder lidar com um complexo, o outro deverá ajustar ou será necessário um tradutor. Muitos desenvolvedores (pelo menos os C / C ++ que eu conheço) tendem a evitar alterações de esquema / design como se fosse um incêndio, que mais tarde resulta em um sistema ruim. Se outro componente não puder se ajustar, talvez seja mal decomposto / projetado. Se há outras razões para não mudar, então você provavelmente deve considerar o uso de um hardware diferente
Whoot

0

BEIJO e YAGNI.
Escolha a opção 1 e se ela se tornar um problema real - só então reitere nela.

Pelo menos para casos de uso semelhantes com formatos binários semelhantes, quando apenas alguns valores precisavam ser preenchidos dessa maneira, essa é a solução mais simples / mais fácil / melhor. Se você precisar fazer isso em cada parte dos dados - pode ser uma falha na arquitetura.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.