Pergunta

Eu tenho uma simulação que lê grandes arquivos de dados binários que nós criamos (10s a 100s de GB). Usamos binário por razões de velocidade. Esses arquivos são dependentes do sistema, convertido a partir de arquivos de texto em cada sistema que corremos, por isso não estou preocupado com a portabilidade. Os arquivos atualmente muitos exemplos de uma estrutura POD, escritas com fwrite.

Eu preciso mudar a estrutura, então eu quero adicionar um cabeçalho que tem um número de versão arquivo nele, que será incrementado qualquer momento as mudanças struct. Desde que eu estou fazendo isso, eu quero adicionar algumas outras informações também. Estou pensando no tamanho da estrutura, ordem de bytes, e talvez o número svn versão do código que criou o arquivo binário. É outra coisa lá qualquer coisa que possa ser útil a acrescentar?

Foi útil?

Solução

Na minha experiência, tentando adivinhar os dados que você precisa é tempo invariavelmente desperdiçado. O que é importante é estruturar o seu metadados de uma forma que é extensível. Para arquivos XML, que é simples, mas arquivos binários requerem um pouco mais pensamento.

I tendem a armazenar metadados em uma estrutura no final do arquivo, não o começo. Isso tem duas vantagens:

  • truncado / arquivos sem terminação são facilmente detectado.
  • rodapés
  • Os metadados podem muitas vezes ser anexados a arquivos existentes, sem impactando o seu código de leitura.

O rodapé de metadados mais simples que eu uso é algo como isto:

struct MetadataFooter{
  char[40] creatorVersion;
  char[40] creatorApplication;
  .. or whatever
} 

struct FileFooter
{
  int64 metadataFooterSize;  // = sizeof(MetadataFooter)
  char[10] magicString;   // a unique identifier for the format: maybe "MYFILEFMT"
};

Depois que os dados brutos, o rodapé de metadados e depois o rodapé arquivo são escritos.

Ao ler o arquivo, procure o fim - sizeof (FileFooter). Leia o rodapé, e verificar a strings mágicas. Em seguida, procurar para trás de acordo com metadataFooterSize e ler os metadados. Dependendo do tamanho de rodapé contidas no arquivo, você pode usar os valores padrão para os campos em falta.

Como aponta KeithB , você pode até mesmo usar esta técnica para armazenar os metadados como uma string XML, dando as vantagens de ambos metadados totalmente extensível, com a compacidade ea velocidade de dados binário.

Outras dicas

Para grandes binários eu olhar seriamente HDF5 (Google por isso). Mesmo se não é algo que você deseja adotar isto pode apontá-lo em algumas direções úteis na concepção de seus próprios formatos.

Para grandes binários, além de o número da versão I tendem a colocar uma contagem de registro e CRC, a razão é que grandes binários são muito mais propensos a ficar truncado e / ou danificados ao longo do tempo ou durante a transferência do que os menores. Eu encontrei recentemente para meu horror que o Windows não lidar com isso muito bem em tudo, como eu costumava Explorer para copiar cerca de 2 TB através de um par de centenas de arquivos para um dispositivo NAS anexado, e encontrou 2-3 arquivos em cada cópia foram danificados (não completamente copiado).

Um identificador para o tipo de arquivo será útil se você vai ter outras estruturas escritos para arquivos binários mais tarde. Talvez esta poderia ser uma corda curta, então você pode ver por um olhar para o arquivo (via editor hex) que ele contém.

Se eles são tão grande, eu reservar um pedaço saudável (64 K?) De espaço no início do arquivo e colocar os metadados existem em formato XML seguido de um caractere de fim-de-arquivo (Ctrl-Z para DOS / Windows, ctrl-D para unix?). Dessa forma, você pode examinar e analisar os metadados facilmente com a vasta gama de conjuntos de ferramentas para fora lá para XML.

Caso contrário, eu ir com o que outras pessoas já disse: timestamp para criação do arquivo, identificador de qual máquina ele é criado em, basicamente, qualquer outra coisa que você pode pensar para fins de diagnóstico. E, idealmente, você deve incluir a definição do formato de estrutura em si. Se você está mudando a estrutura, muitas vezes, é uma grande dor para manter a versão adequada do código em torno de ler vários formatos de arquivos de dados antigos.

Uma das grandes vantagens de HDF5 como @highpercomp mencionou, é que você simplesmente não precisa se preocupar com mudanças no formato de estrutura, desde que você tem alguma convenção de que os nomes e tipos de dados são. Os nomes estrutura e tipos de dados são armazenados no próprio arquivo, assim você pode explodir o seu código C em pedacinhos e isso não importa, você ainda pode recuperar dados de um arquivo HDF5. Ele permite que você se preocupar menos com o formato de dados e muito mais no estrutura dos dados, ou seja, eu não me importo com a seqüência de bytes, que é problema do HDF5, mas eu se preocupam com nomes de campo e assim por diante.

Outra razão I como HDF5 é que você pode optar por compressão uso, o que leva uma quantidade muito pequena de tempo e pode dar-lhe enormes vitórias em espaço de armazenamento se os dados é lenta mudança ou quase o mesmo, exceto por alguns blips errantes de interestingness.

@rstevens disse 'um identificador para o tipo de arquivo' ... bons conselhos. Convencionalmente, que é chamado um número mágico e, em um arquivo, não é um termo de abuso (ao contrário de código, onde é um termo de abuso). Basicamente, é algum número - tipicamente, pelo menos, 4 bytes, e eu normalmente garantir que pelo menos um desses bytes não é ASCII - que você pode usar para validar que o arquivo é do tipo que você espera com uma baixa probabilidade de ser confundido . Você também pode escrever uma regra no / etc / magic (ou equivalente local) para relatar que os arquivos contendo o seu número mágico é o tipo de arquivo especial.

Você deve incluir um número de versão formato de arquivo. No entanto, eu recomendo não usar o número SVN do código. Seu código pode mudar quando o formato de arquivo não.

Além de todas as informações que você precisa para o esquema de versionamento, adicionar detalhes que possam ser de valor se você estiver solucionando um problema. Por exemplo:

  • marcas de tempo de quando o arquivo foi criado e atualização (se aplicável).
  • a cadeia de versão da compilação (o ideal é que você tem uma cadeia de versão que está em cada compilação 'oficial' auto-incrementada ... isso é diferente para a versão do esquema de arquivo).
  • o nome do sistema de criação do arquivo, e talvez outras estatísticas que são relevantes para a sua aplicação

Nós achamos isso é muito útil (a) no sentido de obter informações que de outra forma teria de pedir ao cliente para fornecer e (b) obter informações corretas - é incrível como muitos clientes relatam que eles estão executando uma versão diferente do software ao que alega a dados!

Você pode considerar colocar um deslocamento em uma posição fixa no cabeçalho, que lhe diz onde os dados reais começa no arquivo arquivo. Isso permitiria que você alterar o tamanho do cabeçalho quando necessário.

Em alguns casos, eu coloquei o valor 0x12345678 no cabeçalho para que eu pudesse detectar se o formato de arquivo, combinava com a endianism da máquina que foi processá-lo.

Como a minha experiência com shows de configuração de equipamentos de telecomunicações e atualizações de firmware você realmente só precisa de vários bytes pré-definidos no início (isso é importante) que começa a partir da versão (parte fixa de cabeçalho). Resto do cabeçalho é opcional, indicando versão apropriada você sempre pode mostrar como processá-lo. importante aqui é que você seria melhor lugar parte 'variável' de cabeçalho no final do arquivo. Se você planeja operações no cabeçalho sem modificar o conteúdo do arquivo em si. Também esta simplificar 'anexar' operações que deve recalcular parte do cabeçalho variável.

É bom ter recursos para cabeçalho de tamanho fixo (no início):

  • campo comum 'tamanho' (incluindo cabeçalho).
  • Algo como CRC32 (incluindo cabeçalho).

OK, para XML parte variável ou algum formato bastante extensível no cabeçalho é boa idéia, mas é realmente necessário? Eu tive muita experiência com a codificação ASN ... na maioria dos casos seu uso foi ultrapassado.

Bem, talvez você terá a compreensão adicional quando você olhar para coisas como formato TPKT que é descrito em RFC 2126 (capítulo 4.3).

Se você está colocando um número de versão no cabeçalho você pode mudar essa versão a qualquer momento você precisa mudar a estrutura POD ou adicionar novos campos para o cabeçalho.

Portanto, não adicionar coisas para o cabeçalho agora, porque ele pode ser interessante. Está apenas a criação de código que você tem que manter, mas que tem pouco valor real.

Para arquivos grandes, você pode querer adicionar definições de dados, para que o seu formato de arquivo torna-se auto-descrição.

Meu variação combina Roddy e abordagens de Jason S.

Em resumo -. Colocar metadados texto formatado no final do arquivo com uma maneira de determinar seu comprimento armazenados em outros lugares

1) Coloque um campo de comprimento no início do seu arquivo para você saber o comprimento dos metadados no final ao invés de assumir um comprimento fixo. Dessa forma, para obter os metadados você acabou de ler que o campo inicial de comprimento fixo e, em seguida, obter o blob de metadados a partir do final do arquivo.

2) Use XML ou YAML ou JSON para os metadados. Isto é especialmente útil / seguro se os metadados é anexado no final, porque ninguém lê o arquivo vai pensar automaticamente que é tudo XML só porque ele começa com XML.

A única desvantagem nesta abordagem é quando os seus metadados cresce, você tem que atualizar tanto o chefe do arquivo e a cauda, ??mas é provável que outras partes terão sido atualizados de qualquer maneira. Se é apenas atualizando trivia como um último acesso data, então o comprimento de metadados não vai mudar por isso só precisa de uma atualização no local.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top