Considerações ao projetar um tipo de arquivo

8

Estou prestes a começar a escrever um processo para salvar alguma estrutura de dados do código em um arquivo de algum tipo proprietário, ainda não definido. No entanto, nunca criei um tipo ou estrutura de arquivo antes.

  • Em geral, existem coisas que devo considerar antes de iniciar meu design?
  • Existem boas práticas aceitas aqui? Más práticas que devo evitar?
  • Algum absoluto faz e não faz?
Andy Hunt
fonte
3
Olá a partir de 2016! Esta é a definição do livro didático de uma pergunta muito ampla :) Ajudaria se você fornecesse detalhes sobre o que está tentando alcançar. A maioria dos formatos de arquivos proprietários são projetados para algo . Quais são os seus requisitos?
Andrés F.
Não se esqueça do principal benefício de usar um formato padrão: outras ferramentas e aplicativos poderão ingeri-lo mais facilmente. E você pode não ser a única pessoa que trabalha com esses dados. Se você trabalhar com esse princípio em mente, seu software será mais flexível e isso poderá simplificar as coisas.
Joey Adams

Respostas:

20

Primeiro, tente encontrar um formato que seja próximo o suficiente do que você está prestes a construir. Em geral, é melhor usar o formato de alguém do que inventar o seu próprio, mesmo que o formato pareça um pouco mais complexo do que o necessário 1 .

Se você não conseguir encontrar um formato pronto adequado, veja se pode criar seu próprio sobre um formato de uso geral existente, como XML ou XML binário . Isso deve ser possível em quase todos os casos, quando você está prestes a iniciar um novo formato de arquivo. O XML baseado em texto ocupa mais espaço, mas fornece aos humanos alguma medida de legibilidade. No entanto, se você estiver usando a codificação Base-64 dentro de um arquivo XML, isso é uma indicação clara de que você deveria ter usado uma codificação binária.

No que diz respeito às boas e más práticas, certifique-se de não incorporar o recurso de hardware da sua plataforma de destino inicial ao design do formato do arquivo. Especificamente, verifique se seus números estão armazenados em um formato que possa ser lido corretamente em plataformas com endianness diferente do gravador e se as seqüências de caracteres voltadas para o usuário estão armazenadas no UNICODE.

Outra boa prática é incluir um cabeçalho no qual é possível determinar o tipo do seu arquivo, caso sua extensão esteja ausente ou incorreta. É uma boa ideia incluir uma versão do seu formato de arquivo no cabeçalho. Isso permitiria alterar o formato posteriormente e permanecer compatível com versões anteriores.

Se possível, não torne seu formato dependente das especificidades do mecanismo de serialização padrão incorporado à sua plataforma. Por exemplo, objetos Java serializados em binários não produzem um bom formato de arquivo 2 .

Por fim, decida se seus arquivos precisam ser streamable . Isso introduz complexidade adicional, porque é possível interpretar "quadros" individuais do seu arquivo isoladamente. Nos casos em que você precisa de capacidade de estruturação, no entanto, você quase sempre deve conseguir localizar um formato de arquivo adequado que já exista.


1 Por outro lado, você deve evitar formatos que exijam esforços extraordinários para suportar a complexidade exigida pelo seu aplicativo.

2 Isso não significa, no entanto, que você não deve tentar integrar de forma personalizada a leitura e gravação do seu novo formato com o esquema de serialização da sua plataforma, apenas que você não deve confiar nos mecanismos padrão de serialização.

dasblinkenlight
fonte
3
Unicode não é um formato. É apenas um mapeamento. UTF-8 é um formato e geralmente é considerado o formato adequado para cadeias de texto portáteis (a menos que você esteja manipulando texto CJK; nesse caso, acho que UTF-16LE é provavelmente o próximo formato mais comum para cadeias de caracteres)
squarewav
12

A primeira coisa que você deve considerar é se você realmente precisa de um novo formato ou se pode usar um formato já existente. Considere usar o SQLite; se você pode adaptar suas necessidades ao modelo RDBMS, isso pode poupar muitas dores de cabeça. Além disso, considere usar XML ou JSON, isso evitará que você precise escrever seu próprio analisador.

Se você precisar criar seu próprio formato, a primeira consideração é se você deseja um formato de texto ou um formato binário. Existem vantagens para ambos. Um formato de texto é uma grande vitória para a portabilidade e tem a vantagem de ser mais fácil para um ser humano ler ou editar. Um formato binário pode ser mais eficiente, mas possui muitos problemas de portabilidade. Não fique tentado a ler bytes diretamente em variáveis; você se arrependerá se precisar portar o código para outra plataforma.

Dirk Holsopple
fonte
Lembre-se também, ao criar seu próprio formato, que você DEVE levar em consideração arquivos quebrados e garantir que eles não quebrem seu aplicativo. Além disso, se estiver usando XML, por favor, pelo amor de tudo o que é precioso para você: USE UM PARSER XML. Não importa qual (seu idioma pode fornecer um), mas NÃO SEJA XML.
Michael Kohne
SQLite se você precisar de um banco de dados com registros individuais que possam ser alterados instantaneamente. JSON, se estiver OK, leia todos os dados na memória, modifique-os na memória e, em seguida, escreva-os novamente no arquivo.
precisa saber é o seguinte
1
@MichaelKohne: O mesmo para JSON. Eu estimaria que 10% das perguntas do iOS são sobre falhas quando algum JSON contém um nulo, onde espera uma string.
gnasher729
2

Sua primeira e mais importante decisão é usar um formato binário ou baseado em texto. O binário é o caminho a seguir quando você precisa despejar grandes quantidades em dados que não são de cadeia. Mas tem desvantagens significativas:

  • Dados binários não são legíveis por humanos. Como tal, torna a depuração e / ou ajustes de dados que já estão no disco muito mais difíceis. Essa é uma das razões pelas quais a filosofia do UNIX abraça tão fortemente os arquivos baseados em texto.

  • Formatos binários não se prestam à expansão futura. Embora isso possa ser feito, pontos de expansão precisam ser incorporados ao formato desde o início. Normalmente, estes são

    1. um número / sequência mágica que identifica o formato

    2. um número de versão do formato

    3. campos reservados em posições estratégicas, que devem ser inicializadas em zero

    Os dois primeiros geralmente aparecem logo no início do arquivo, enquanto os campos reservados geralmente estão espalhados pelo arquivo.


Agora, se você seguir a rota baseada em texto, aqui estão algumas coisas para pensar:

  • Qualquer formato baseado em texto define um novo mini-idioma. Saiba disso e use-o para sua vantagem.

  • Tente manter as regras do seu mini-idioma o mais simples possível. Não há lugar onde o princípio do KISS seja mais importante do que ao projetar um formato de arquivo baseado em texto.

  • Tente tornar seus arquivos auto-explicativos.

  • Não imponha restrições desnecessárias, como onde espaços em branco podem aparecer e qual a quantidade.

  • Dê uma boa olhada em vários formatos de arquivo diferentes desenvolvidos para o UNIX. Isso pode lhe dar algumas boas idéias.

  • Se possível, use ou adapte / expanda / restrinja um formato de arquivo existente. O formato json é um ponto de partida bastante legível e bom. (Pelo menos, muito melhor que XML, que é uma dor de se ler para humanos.)

  • Se o tamanho do arquivo for um problema, considere o uso de um formato baseado em texto, mas passe-o por um dos compressores padrão, como gzipou lzma. Os compressores padrão adoram entradas assim.


Se você seguir a rota binária, veja algumas coisas a serem observadas:

  • Você deve ter um cabeçalho com um número / string mágico e um número de versão. Normalmente, isso vai para o início do arquivo, mas também pode ir para o final do arquivo. Alguns arquivos podem até ter dois cabeçalhos diferentes na frente e atrás, fornecendo duas visualizações independentes dos dados.

  • Você deve ter um índice e deve tentar manter suas partes juntas. Isso permite que um leitor descubra rapidamente o que há dentro do arquivo, sem ter que verificar a coisa toda. Se você não conseguir fazer isso, poderá acabar lendo tudo duas vezes.

  • Se você tiver bits do arquivo acessíveis apenas como uma sequência, e não através de uma estrutura de índice, inclua pelo menos um campo de comprimento para cada registro na sequência. Os campos de índice ou tamanho são requisitos para leitores que não entendem todos os detalhes do seu formato e precisam pular partes dele como caixas pretas. (Obrigado a Jules por este.)

  • Todo objeto de dados dentro do arquivo precisa conter pelo menos um campo reservado para expansão futura. Isso não precisa ser grande, mas precisa estar lá. Porque, se não for, não há lugar onde você possa reconhecer os recursos futuros.

  • Você precisa levar em consideração as endianess. Normalmente, isso significa que você decide uma vez se seus arquivos devem ser codificados em big endian ou little endian byte order e se atenha a essa decisão: lidar com endianess como esse é um incômodo, mas não é tão ruim quanto ter que explicar duas versões diferentes de endianess no arquivo.

  • Seja generoso nas larguras dos campos que você fornecer. Especialmente, quando você precisar codificar deslocamentos no arquivo, use sempre 64 bits. Muitas dores de cabeça foram causadas por designers de formato de arquivo que eram muito conservadores com a quantidade de bits alocados.

cmaster - restabelece monica
fonte
Vou adicionar outro para arquivos binários: se você tiver uma sequência de registros de tipos variados (que é uma estrutura muito útil), NÃO assuma que qualquer leitor do arquivo compreenda todos os tipos. Use indicadores de comprimento para que registros desconhecidos possam ser ignorados.
Jules
@ Jules Você está certo :-) eu adicionei isso como ponto 3 para os arquivos binários.
cmaster - restabelece monica
0

Realmente depende do que você está fazendo. Deve ser o mais simples possível e não mais simples. Eu vejo muitas outras pessoas pressionando XML. Eu desencorajo fortemente o uso de XML. XML é uma bagunça super especificada. A primeira pergunta seria se suas estruturas de dados têm ramificações. Significado São listas de listas ou listas de mapas ou algo assim? Se não, uma sequência simples de registros de texto pode ser boa. CSV talvez.

Se você precisar de desempenho ou acesso aleatório, o binário é bom. Defina uma sequência de registros em que cada registro contém uma sequência de dados que têm um tamanho específico, como um número inteiro endian de 4 bytes para algum número ou um número inteiro de 2 bytes que especifica o número de bytes para uma sequência UTF-8. Faça com que cada registro comece com um número inteiro especificando o tamanho do registro, para que todo o arquivo possa ser verificado sem realmente ler o conteúdo dos registros. Isso também permite codificar registros in situ (o que significa que você pode mapear o arquivo, codificar o registro e atualizar o tamanho depois para minimizar as cópias desnecessárias). Esse é o tipo de coisa que você não pode fazer com XML.

squarewav
fonte